harvestr 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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