harvestr 0.0.1

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 ADDED
@@ -0,0 +1 @@
1
+ 0.0.1 - initial release
data/License ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Squeejee
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Notes ADDED
File without changes
@@ -0,0 +1,17 @@
1
+ = harvestr
2
+
3
+ A Ruby wrapper for the Harvest and Co-op APIs.
4
+
5
+ == examples
6
+
7
+ See the examples directory.
8
+
9
+ http://github.com/squeejee/harvestr/tree/master/examples
10
+
11
+ == docs
12
+
13
+ http://rdoc.info/projects/squeejee/harvestr
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2009 Squeejee. See LICENSE for details.
@@ -0,0 +1,102 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "harvestr"
8
+ gem.summary = %Q{wrapper for the Harvest api}
9
+ gem.email = "jim@squeejee.com"
10
+ gem.homepage = "http://github.com/squeejee/harvestr"
11
+ gem.authors = ["Wynn Netherland", "Jim Mulholland", "Jason Derrett"]
12
+ gem.rubyforge_project = "harvestr"
13
+ gem.files = FileList["[A-Z]*", "{examples,lib,test}/**/*"]
14
+
15
+ gem.add_dependency('mash', '0.0.3')
16
+ gem.add_dependency('httparty', '0.4.3')
17
+
18
+ gem.add_development_dependency('thoughtbot-shoulda')
19
+ gem.add_development_dependency('jeremymcanally-matchy')
20
+ gem.add_development_dependency('mocha')
21
+ gem.add_development_dependency('fakeweb', '1.2.5')
22
+ gem.add_development_dependency('mash')
23
+ end
24
+ rescue LoadError
25
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
26
+ end
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/*_test.rb'
32
+ test.verbose = false
33
+ end
34
+
35
+ begin
36
+ require 'rcov/rcovtask'
37
+ Rcov::RcovTask.new do |test|
38
+ test.libs << 'test'
39
+ test.pattern = 'test/**/*_test.rb'
40
+ test.verbose = true
41
+ end
42
+ rescue LoadError
43
+ task :rcov do
44
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
45
+ end
46
+ end
47
+
48
+
49
+ task :default => :test
50
+
51
+ require 'rake/rdoctask'
52
+ Rake::RDocTask.new do |rdoc|
53
+ if File.exist?('VERSION.yml')
54
+ config = YAML.load(File.read('VERSION.yml'))
55
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
56
+ else
57
+ version = ""
58
+ end
59
+
60
+ rdoc.rdoc_dir = 'rdoc'
61
+ rdoc.title = "harvestr #{version}"
62
+ rdoc.rdoc_files.include('README*')
63
+ rdoc.rdoc_files.include('lib/**/*.rb')
64
+ end
65
+
66
+ begin
67
+ require 'rake/contrib/sshpublisher'
68
+ namespace :rubyforge do
69
+
70
+ desc "Release gem and RDoc documentation to RubyForge"
71
+ task :release => ["rubyforge:release:gem", "rubyforge:release:website", "rubyforge:release:docs"]
72
+
73
+ namespace :release do
74
+ desc "Publish RDoc to RubyForge."
75
+ task :docs => [:rdoc] do
76
+ config = YAML.load(
77
+ File.read(File.expand_path('~/.rubyforge/user-config.yml'))
78
+ )
79
+
80
+ host = "#{config['username']}@rubyforge.org"
81
+ remote_dir = "/var/www/gforge-projects/harvestr/rdoc"
82
+ local_dir = 'rdoc'
83
+
84
+ Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload
85
+ end
86
+
87
+ task :website do
88
+ config = YAML.load(
89
+ File.read(File.expand_path('~/.rubyforge/user-config.yml'))
90
+ )
91
+
92
+ host = "#{config['username']}@rubyforge.org"
93
+ remote_dir = "/var/www/gforge-projects/harvestr/"
94
+ local_dir = 'website'
95
+
96
+ Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload
97
+ end
98
+ end
99
+ end
100
+ rescue LoadError
101
+ puts "Rake SshDirPublisher is unavailable or your rubyforge environment is not configured."
102
+ end
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 0
4
+ :patch: 1
@@ -0,0 +1,13 @@
1
+ require 'lib/harvestr'
2
+ Harvest.domain = 'yourdomain'
3
+ Harvest.email = 'you@example.com'
4
+ Harvest.password = 'yourpass'
5
+ client = Harvest::TimeTracking.new
6
+
7
+ # add a new entry
8
+ client.add({:project_id => 408960, :task_id => 333866, :notes => 'Writing TPS reports', :hours => 1.21})
9
+ #=> <Mash client="Pengwynn Group" hours=1.21 id=14319479 notes="Writing TPS reports" project="Internal" project_id="408960" task="Project Management" task_id="333866">
10
+
11
+ # toggle an entry
12
+ client.toggle(14319479)
13
+ #=> <Mash client="Pengwynn Group" hours=1.21 id=14319479 notes="Writing TPS reports" project="Internal" project_id="408960" task="Project Management" task_id="333866" timer_started_at=Sat Aug 01 19:14:07 UTC 2009>
@@ -0,0 +1,29 @@
1
+ module Harvest
2
+ class Base
3
+ include HTTParty
4
+ format :xml
5
+ headers({'Accept' => 'text/xml'})
6
+
7
+ attr_accessor :domain, :email, :password, :use_ssl
8
+
9
+ def initialize(options={})
10
+ @domain = options[:domain] ||= Harvest.domain
11
+ @email = options[:email] ||= Harvest.email
12
+ @password = options[:password] ||= Harvest.password
13
+ @use_ssl = options[:use_ssl] ||= Harvest.use_ssl
14
+
15
+ self.class.base_uri "#{@domain}.harvestapp.com"
16
+ self.class.basic_auth(@email, @password)
17
+ end
18
+
19
+ def rate_limit_status
20
+ request = Mash.new(self.class.get('/account/rate_limit_status')).request
21
+ %w(count time_frame_limit max_calls lockout_seconds).each do |key|
22
+ request[key] = request[key].to_i
23
+ end
24
+ request
25
+ end
26
+
27
+
28
+ end
29
+ end
@@ -0,0 +1,34 @@
1
+ module Harvest
2
+ class Reports < Harvest::Base
3
+ # GET /projects
4
+ def projects
5
+ Mash.new(self.class.get("/projects")).projects
6
+ end
7
+
8
+ # GET /projects/#{project_id}/entries?from=YYYYMMDD&to=YYYYMMDD
9
+ def project_entries(project_id, from, to, user_id=nil)
10
+ opts = {:from => from, :to => to}
11
+ opts[:user_id] = user_id if user_id
12
+ Mash.new(self.class.get("/projects/#{project_id}/entries", :query => opts)).day_entries
13
+ end
14
+
15
+ def total_project_hours(project_id, from, to, user_id=nil)
16
+ pe = project_entries(project_id, from, to, user_id)
17
+ total = 0.0
18
+ if pe
19
+ pe.each {|msh| total += msh.hours}
20
+ end
21
+ total
22
+ end
23
+
24
+ # [['proj1', 25.5], ['proj2', 33.3]]
25
+ def project_totals(from=7.days.ago, to=Date.today)
26
+ @pt = []
27
+ projects.each do |p|
28
+ hrs = total_project_hours(p.id, from, to)
29
+ @pt << [p.name, hrs] if hrs > 0
30
+ end
31
+ @pt
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,44 @@
1
+ module Harvest
2
+ class TimeTracking < Harvest::Base
3
+
4
+ # GET /daily
5
+ # GET /daily/#{day_of_the_year}/#{year}
6
+ def daily(date=nil)
7
+ date = DateTime.parse(date) if date.is_a?(String)
8
+ if date.respond_to?(:yday)
9
+ response = self.class.get("/daily/#{date.yday}/#{date.year}")
10
+ else
11
+ response = self.class.get('/daily')
12
+ end
13
+ response
14
+ end
15
+
16
+ # GET /daily/show/#{day_entry_id}
17
+ def entry(id)
18
+ Mash.new(self.class.get("/daily/show/#{id}")).add.day_entry
19
+ end
20
+
21
+ # GET /daily/timer/#{day_entry_id}
22
+ def toggle(id)
23
+ Mash.new(self.class.get("/daily/timer/#{id}")).timer.day_entry
24
+ end
25
+
26
+ # POST /daily/add
27
+ def add(body)
28
+ Mash.new(self.class.post("/daily/add", :body => body)).add.day_entry
29
+ end
30
+
31
+ # DELETE /daily/delete/#{day_entry_id}
32
+ def delete(id)
33
+ Mash.new(self.class.delete("/daily/delete/#{id}"))
34
+ end
35
+
36
+ # POST /daily/update/#{day_entry_id}
37
+ def update(id, body)
38
+ # current_entry = entry(id)
39
+ # body = current_entry.merge(Mash.new body.to_hash)
40
+ # puts body.inspect
41
+ Mash.new(self.class.post("/daily/update/#{id}", :body => body)).add.day_entry
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,60 @@
1
+ require 'forwardable'
2
+ require 'rubygems'
3
+
4
+ gem 'mash', '0.0.3'
5
+ require 'mash'
6
+
7
+ gem 'httparty', '0.4.3'
8
+ require 'httparty'
9
+
10
+ class APIKeyNotSet < StandardError; end
11
+
12
+ module Harvest
13
+
14
+ def self.domain=(value)
15
+ @domain = value
16
+ end
17
+
18
+ def self.domain
19
+ @domain
20
+ end
21
+
22
+ def self.email=(value)
23
+ @email = value
24
+ end
25
+
26
+ def self.email
27
+ @email
28
+ end
29
+
30
+ def self.password=(value)
31
+ @password = value
32
+ end
33
+
34
+ def self.password
35
+ @password
36
+ end
37
+
38
+ def self.use_ssl=(value)
39
+ @use_ssl = !!value
40
+ end
41
+
42
+ def self.use_ssl
43
+ @use_ssl ||= false
44
+ end
45
+
46
+ def self.default_options
47
+ {
48
+ :domain => @domain,
49
+ :email => @email,
50
+ :password => @password,
51
+ :use_ssl => @use_ssl
52
+ }
53
+ end
54
+ end
55
+
56
+ directory = File.expand_path(File.dirname(__FILE__))
57
+
58
+ require File.join(directory, 'harvest', 'base')
59
+ require File.join(directory, 'harvest', 'time_tracking')
60
+ require File.join(directory, 'harvest', 'reports')
@@ -0,0 +1,62 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <daily>
3
+ <for_day type="date">Sat, 01 Aug 2009</for_day>
4
+ <day_entries>
5
+ <day_entry>
6
+ <id type="integer">14316546</id>
7
+ <spent_at type="date">2009-08-01</spent_at>
8
+ <user_id type="integer">86342</user_id>
9
+ <client>Pengwynn Group</client>
10
+ <project_id>408960</project_id>
11
+ <project>Internal</project>
12
+ <task_id>333865</task_id>
13
+ <task>Admin</task>
14
+ <hours type="float">1.34</hours>
15
+ <notes></notes>
16
+ <created_at type="datetime">Sat, 01 Aug 2009 02:19:00 +0000</created_at>
17
+ </day_entry>
18
+ <day_entry>
19
+ <id type="integer">14319479</id>
20
+ <spent_at type="date">2009-08-01</spent_at>
21
+ <user_id type="integer">86342</user_id>
22
+ <client>Pengwynn Group</client>
23
+ <project_id>408960</project_id>
24
+ <project>Internal</project>
25
+ <task_id>333866</task_id>
26
+ <task>Project Management</task>
27
+ <hours type="float">1.34</hours>
28
+ <notes></notes>
29
+ <created_at type="datetime">Sat, 01 Aug 2009 19:09:03 +0000</created_at>
30
+ </day_entry>
31
+ </day_entries>
32
+ <projects>
33
+ <project>
34
+ <name>Internal</name>
35
+ <code></code>
36
+ <id type="integer">408960</id>
37
+ <client>Pengwynn Group</client>
38
+ <tasks>
39
+ <task>
40
+ <name>Admin</name>
41
+ <id type="integer">333865</id>
42
+ <billable type="boolean">false</billable>
43
+ </task>
44
+ <task>
45
+ <name>Business Development</name>
46
+ <id type="integer">333867</id>
47
+ <billable type="boolean">false</billable>
48
+ </task>
49
+ <task>
50
+ <name>Project Management</name>
51
+ <id type="integer">333866</id>
52
+ <billable type="boolean">false</billable>
53
+ </task>
54
+ <task>
55
+ <name>Vacation</name>
56
+ <id type="integer">333868</id>
57
+ <billable type="boolean">false</billable>
58
+ </task>
59
+ </tasks>
60
+ </project>
61
+ </projects>
62
+ </daily>
@@ -0,0 +1,16 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <add>
3
+ <day_entry>
4
+ <id type="integer">14316546</id>
5
+ <spent_at type="date">2009-08-01</spent_at>
6
+ <user_id type="integer">86342</user_id>
7
+ <client>Pengwynn Group</client>
8
+ <project_id>408960</project_id>
9
+ <project>Internal</project>
10
+ <task_id>333865</task_id>
11
+ <task>Admin</task>
12
+ <hours type="float">0.00</hours>
13
+ <notes></notes>
14
+ <created_at type="datetime">Sat, 01 Aug 2009 02:19:00 +0000</created_at>
15
+ </day_entry>
16
+ </add>
@@ -0,0 +1,55 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <day-entries type="array">
3
+ <day-entry>
4
+ <created-at type="datetime">2009-08-01T02:21:32Z</created-at>
5
+ <hours type="decimal">4.5</hours>
6
+ <id type="integer">14316565</id>
7
+ <is-billed type="boolean">false</is-billed>
8
+ <is-closed type="boolean">false</is-closed>
9
+ <notes>This is a test</notes>
10
+ <project-id type="integer">408960</project-id>
11
+ <spent-at type="date">2009-07-31</spent-at>
12
+ <task-id type="integer">333865</task-id>
13
+ <timer-started-at type="datetime" nil="true"></timer-started-at>
14
+ <user-id type="integer">86342</user-id>
15
+ </day-entry>
16
+ <day-entry>
17
+ <created-at type="datetime">2009-08-01T02:21:46Z</created-at>
18
+ <hours type="decimal">2.0</hours>
19
+ <id type="integer">14316569</id>
20
+ <is-billed type="boolean">false</is-billed>
21
+ <is-closed type="boolean">false</is-closed>
22
+ <notes>Signing contracts</notes>
23
+ <project-id type="integer">408960</project-id>
24
+ <spent-at type="date">2009-07-31</spent-at>
25
+ <task-id type="integer">333867</task-id>
26
+ <timer-started-at type="datetime" nil="true"></timer-started-at>
27
+ <user-id type="integer">86342</user-id>
28
+ </day-entry>
29
+ <day-entry>
30
+ <created-at type="datetime">2009-08-01T02:19:00Z</created-at>
31
+ <hours type="decimal">0.0</hours>
32
+ <id type="integer">14316546</id>
33
+ <is-billed type="boolean">false</is-billed>
34
+ <is-closed type="boolean">false</is-closed>
35
+ <notes nil="true"></notes>
36
+ <project-id type="integer">408960</project-id>
37
+ <spent-at type="date">2009-08-01</spent-at>
38
+ <task-id type="integer">333865</task-id>
39
+ <timer-started-at type="datetime" nil="true"></timer-started-at>
40
+ <user-id type="integer">86342</user-id>
41
+ </day-entry>
42
+ <day-entry>
43
+ <created-at type="datetime">2009-08-01T19:09:03Z</created-at>
44
+ <hours type="decimal">1.34</hours>
45
+ <id type="integer">14319479</id>
46
+ <is-billed type="boolean">false</is-billed>
47
+ <is-closed type="boolean">false</is-closed>
48
+ <notes></notes>
49
+ <project-id type="integer">408960</project-id>
50
+ <spent-at type="date">2009-08-01</spent-at>
51
+ <task-id type="integer">333866</task-id>
52
+ <timer-started-at type="datetime" nil="true"></timer-started-at>
53
+ <user-id type="integer">86342</user-id>
54
+ </day-entry>
55
+ </day-entries>
@@ -0,0 +1,7 @@
1
+ <request>
2
+ <count>0</count>
3
+ <timeframe_limit>15</timeframe_limit>
4
+ <max_calls>40</max_calls>
5
+ <last_access_at>Sat Aug 01 23:06:55 +0000 2009</last_access_at>
6
+ <lockout_seconds>300</lockout_seconds>
7
+ </request>
@@ -0,0 +1,17 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <timer>
3
+ <day_entry>
4
+ <id type="integer">14319479</id>
5
+ <spent_at type="date">2009-08-01</spent_at>
6
+ <user_id type="integer">86342</user_id>
7
+ <client>Pengwynn Group</client>
8
+ <project_id>408960</project_id>
9
+ <project>Internal</project>
10
+ <task_id>333866</task_id>
11
+ <task>Project Management</task>
12
+ <hours type="float">0.00</hours>
13
+ <notes></notes>
14
+ <created_at type="datetime">Sat, 01 Aug 2009 19:09:03 +0000</created_at>
15
+ <timer_started_at type="datetime">Sat, 01 Aug 2009 23:16:51 +0000</timer_started_at>
16
+ </day_entry>
17
+ </timer>
@@ -0,0 +1,17 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <add>
3
+ <day_entry>
4
+ <id type="integer">14319479</id>
5
+ <spent_at type="date">2009-08-01</spent_at>
6
+ <user_id type="integer">86342</user_id>
7
+ <client>Pengwynn Group</client>
8
+ <project_id>408960</project_id>
9
+ <project>Internal</project>
10
+ <task_id>333866</task_id>
11
+ <task>Project Management</task>
12
+ <hours type="float">1.07</hours>
13
+ <notes>New notes</notes>
14
+ <created_at type="datetime">Sat, 01 Aug 2009 19:09:03 +0000</created_at>
15
+ <timer_started_at type="datetime">Sat, 01 Aug 2009 23:37:29 +0000</timer_started_at>
16
+ </day_entry>
17
+ </add>
@@ -0,0 +1,22 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class BaseTest < Test::Unit::TestCase
4
+ include Harvest
5
+
6
+ context "When using the API" do
7
+ setup do
8
+ Harvest.domain = 'pengwynn'
9
+ Harvest.email = 'pengwynn@example.com'
10
+ Harvest.password = 'OU812'
11
+ @client = Harvest::Base.new
12
+ end
13
+
14
+ should "fetch rate limit status" do
15
+ stub_get "http://pengwynn%40example.com:OU812@pengwynn.harvestapp.com/account/rate_limit_status", 'rate_limit_status.xml'
16
+ status = @client.rate_limit_status
17
+ status.max_calls.should == 40
18
+ status.lockout_seconds.should == 300
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,21 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class ReportsTest < Test::Unit::TestCase
4
+ include Harvest
5
+
6
+ context "When using the TimeTracking API" do
7
+ setup do
8
+ Harvest.domain = 'pengwynn'
9
+ Harvest.email = 'pengwynn@example.com'
10
+ Harvest.password = 'OU812'
11
+ @client = Harvest::Reports.new
12
+ end
13
+
14
+ should "retrieve project entries for a time range as string values" do
15
+ stub_get "http://pengwynn%40example.com:OU812@pengwynn.harvestapp.com/projects/408960/entries?from=20090730&to=20090802", 'project_entries.xml'
16
+ entries = @client.project_entries(408960, '20090730', '20090802')
17
+ entries.size.should == 4
18
+ entries.first.hours.should == 4.5
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,72 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class TimeTrackingTest < Test::Unit::TestCase
4
+ include Harvest
5
+
6
+ context "When using the TimeTracking API" do
7
+ setup do
8
+ Harvest.domain = 'pengwynn'
9
+ Harvest.email = 'pengwynn@example.com'
10
+ Harvest.password = 'OU812'
11
+ @client = Harvest::TimeTracking.new
12
+ end
13
+
14
+ should "retrieve time entries for today" do
15
+ stub_get "http://pengwynn%40example.com:OU812@pengwynn.harvestapp.com/daily", 'daily.xml'
16
+ response = @client.daily
17
+ entries = response.day_entries
18
+ entries.size.should == 2
19
+ entries.first.project.should == 'Internal'
20
+ end
21
+
22
+ should "retrieve time entries for a given day as a string" do
23
+ stub_get "http://pengwynn%40example.com:OU812@pengwynn.harvestapp.com/daily/213/2009", 'daily.xml'
24
+ response = @client.daily('2009-8-1')
25
+ entries = response.day_entries
26
+ entries.class.should == Array
27
+ end
28
+
29
+ should "retrieve time entries for a given day as a DateTime" do
30
+ stub_get "http://pengwynn%40example.com:OU812@pengwynn.harvestapp.com/daily/213/2009", 'daily.xml'
31
+ response = @client.daily(DateTime.parse('2009-08-01'))
32
+ entries = response.day_entries
33
+ entries.class.should == Array
34
+ end
35
+
36
+ should "retrieve a single entry" do
37
+ stub_get "http://pengwynn%40example.com:OU812@pengwynn.harvestapp.com/daily/show/14316546", 'entry.xml'
38
+ entry = @client.entry(14316546)
39
+ entry.id.should == 14316546
40
+ entry.client.should == 'Pengwynn Group'
41
+ end
42
+
43
+ should "toggle the timer" do
44
+ stub_get "http://pengwynn%40example.com:OU812@pengwynn.harvestapp.com/daily/timer/14319479", 'entry.xml'
45
+ entry = @client.toggle(14319479)
46
+ entry.id.should == 14319479
47
+ end
48
+
49
+ should "create a new entry" do
50
+ stub_post "http://pengwynn%40example.com:OU812@pengwynn.harvestapp.com/daily/add", 'entry.xml'
51
+ entry = @client.add({
52
+ :project_id => 408960,
53
+ :task_id => 333865,
54
+ :hours => 3.24,
55
+ :spent_at => Time.now
56
+ })
57
+ entry.id.should == 14316546
58
+ end
59
+
60
+ # should "delete an entry" do
61
+ # FakeWeb.register_uri(:delete, "http://pengwynn%40example.com:OU812@pengwynn.harvestapp.com/delete/14316546", {})
62
+ # @client.delete(14316546)
63
+ # end
64
+
65
+ should "update an entry" do
66
+ stub_post "http://pengwynn%40example.com:OU812@pengwynn.harvestapp.com/daily/update/14316546", 'entry.xml'
67
+ entry = @client.update(14316546, {:notes => 'Writing TPS reports'})
68
+ entry.id.should == 14316546
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,32 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'matchy'
5
+ require 'mocha'
6
+ require 'fakeweb'
7
+
8
+ FakeWeb.allow_net_connect = false
9
+
10
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
11
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
12
+ require 'harvestr'
13
+
14
+ class Test::Unit::TestCase
15
+ end
16
+
17
+ def fixture_file(filename)
18
+ return '' if filename == ''
19
+ file_path = File.expand_path(File.dirname(__FILE__) + '/fixtures/' + filename)
20
+ File.read(file_path)
21
+ end
22
+
23
+ def stub_get(url, filename, status=nil)
24
+ options = {:body => fixture_file(filename)}
25
+ options.merge!({:status => status}) unless status.nil?
26
+
27
+ FakeWeb.register_uri(:get, url, options)
28
+ end
29
+
30
+ def stub_post(url, filename)
31
+ FakeWeb.register_uri(:post, url, :body => fixture_file(filename))
32
+ end
metadata ADDED
@@ -0,0 +1,150 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: harvestr
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Wynn Netherland
8
+ - Jim Mulholland
9
+ - Jason Derrett
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+
14
+ date: 2009-11-16 00:00:00 -06:00
15
+ default_executable:
16
+ dependencies:
17
+ - !ruby/object:Gem::Dependency
18
+ name: mash
19
+ type: :runtime
20
+ version_requirement:
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "="
24
+ - !ruby/object:Gem::Version
25
+ version: 0.0.3
26
+ version:
27
+ - !ruby/object:Gem::Dependency
28
+ name: httparty
29
+ type: :runtime
30
+ version_requirement:
31
+ version_requirements: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - "="
34
+ - !ruby/object:Gem::Version
35
+ version: 0.4.3
36
+ version:
37
+ - !ruby/object:Gem::Dependency
38
+ name: thoughtbot-shoulda
39
+ type: :development
40
+ version_requirement:
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ version:
47
+ - !ruby/object:Gem::Dependency
48
+ name: jeremymcanally-matchy
49
+ type: :development
50
+ version_requirement:
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ - !ruby/object:Gem::Dependency
58
+ name: mocha
59
+ type: :development
60
+ version_requirement:
61
+ version_requirements: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: "0"
66
+ version:
67
+ - !ruby/object:Gem::Dependency
68
+ name: fakeweb
69
+ type: :development
70
+ version_requirement:
71
+ version_requirements: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "="
74
+ - !ruby/object:Gem::Version
75
+ version: 1.2.5
76
+ version:
77
+ - !ruby/object:Gem::Dependency
78
+ name: mash
79
+ type: :development
80
+ version_requirement:
81
+ version_requirements: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: "0"
86
+ version:
87
+ description:
88
+ email: jim@squeejee.com
89
+ executables: []
90
+
91
+ extensions: []
92
+
93
+ extra_rdoc_files:
94
+ - README.rdoc
95
+ files:
96
+ - History
97
+ - License
98
+ - Notes
99
+ - README.rdoc
100
+ - Rakefile
101
+ - VERSION.yml
102
+ - examples/time_tracking.rb
103
+ - lib/harvest/base.rb
104
+ - lib/harvest/reports.rb
105
+ - lib/harvest/time_tracking.rb
106
+ - lib/harvestr.rb
107
+ - test/fixtures/daily.xml
108
+ - test/fixtures/entry.xml
109
+ - test/fixtures/project_entries.xml
110
+ - test/fixtures/rate_limit_status.xml
111
+ - test/fixtures/timer_toggle.xml
112
+ - test/fixtures/update_entry.xml
113
+ - test/harvestr/base_test.rb
114
+ - test/harvestr/reports_test.rb
115
+ - test/harvestr/time_tracking_test.rb
116
+ - test/test_helper.rb
117
+ has_rdoc: true
118
+ homepage: http://github.com/squeejee/harvestr
119
+ licenses: []
120
+
121
+ post_install_message:
122
+ rdoc_options:
123
+ - --charset=UTF-8
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: "0"
131
+ version:
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: "0"
137
+ version:
138
+ requirements: []
139
+
140
+ rubyforge_project: harvestr
141
+ rubygems_version: 1.3.5
142
+ signing_key:
143
+ specification_version: 3
144
+ summary: wrapper for the Harvest api
145
+ test_files:
146
+ - test/harvestr/base_test.rb
147
+ - test/harvestr/reports_test.rb
148
+ - test/harvestr/time_tracking_test.rb
149
+ - test/test_helper.rb
150
+ - examples/time_tracking.rb