harvested 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,3 @@
1
+ README.md
2
+ lib/**/*.rb
3
+ MIT-LICENSE
data/.gitignore CHANGED
@@ -18,6 +18,8 @@ coverage
18
18
  rdoc
19
19
  pkg
20
20
  spec.opts
21
+ doc
22
+ .yardoc
21
23
 
22
24
  ## PROJECT::SPECIFIC
23
25
  features/support/harvest_credentials.yml
data/README.md CHANGED
@@ -8,14 +8,14 @@ This is a Ruby wrapper for the [Harvest API](http://www.getharvest.com/).
8
8
 
9
9
  ## Examples
10
10
 
11
- harvest = Harvest.client('yoursubdomain', 'yourusername', 'yourpassword', :ssl => false) # you can enable SSL if your account supports it
11
+ harvest = Harvest.client('yoursubdomain', 'yourusername', 'yourpassword')
12
12
  harvest.projects() # list out projects
13
13
 
14
14
  client = Harvest::Client.new(:name => "Billable Company LTD.")
15
15
  client = harvest.clients.create(client)
16
16
  harvest.clients.find(client.id) # returns a Harvest::Client
17
17
 
18
- You can find more examples in `/examples`
18
+ You can find more examples in `/examples` and in the documentation for Harvest::Base
19
19
 
20
20
  ## Hardy Client
21
21
 
@@ -23,11 +23,12 @@ The guys at Harvest built a great API, but there are always dangers in writing c
23
23
 
24
24
  Using `Harvested#client` your code needs to handle all these situations. However you can also use `Harvested#hardy_client` which will retry errors and wait for Rate Limit resets.
25
25
 
26
- harvest = Harvest.hardy_client('yoursubdomain', 'yourusername', 'yourpassword', :ssl => false)
26
+ harvest = Harvest.hardy_client('yoursubdomain', 'yourusername', 'yourpassword')
27
27
  harvest.projects() # This will wait for the Rate Limit reset if you have gone over your limit
28
28
 
29
29
  ## Links
30
30
 
31
+ * [Harvested Documentation](http://rdoc.info/projects/zmoazeni/harvested)
31
32
  * [Harvest API Documentation](http://www.getharvest.com/api)
32
33
  * [Source Code for Harvested](http://github.com/zmoazeni/harvested)
33
34
  * [Pivotal Tracker for Harvested](http://www.pivotaltracker.com/projects/63260)
data/Rakefile CHANGED
@@ -6,7 +6,7 @@ begin
6
6
  Jeweler::Tasks.new do |gem|
7
7
  gem.name = "harvested"
8
8
  gem.summary = %Q{A Ruby Wrapper for the Harvest API http://www.getharvest.com/}
9
- gem.description = %Q{Harvested wraps the Harvest API concisely without the use of Rails dependencies. More information about the Harvest API can be found at http://www.getharvest.com/api}
9
+ gem.description = %Q{Harvested wraps the Harvest API concisely without the use of Rails dependencies. More information about the Harvest API can be found on their website (http://www.getharvest.com/api). For support hit up the Mailing List (http://groups.google.com/group/harvested)}
10
10
  gem.email = "zach.moazeni@gmail.com"
11
11
  gem.homepage = "http://github.com/zmoazeni/harvested"
12
12
  gem.authors = ["Zach Moazeni"]
@@ -50,3 +50,12 @@ rescue LoadError
50
50
  end
51
51
 
52
52
  task :default => %w(spec features)
53
+
54
+ begin
55
+ require 'yard'
56
+ YARD::Rake::YardocTask.new
57
+ rescue LoadError
58
+ task :yardoc do
59
+ abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
60
+ end
61
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.3.1
data/examples/basics.rb CHANGED
@@ -4,7 +4,7 @@ subdomain = 'yoursubdomain'
4
4
  username = 'yourusername'
5
5
  password = 'yourpassword'
6
6
 
7
- harvest = Harvest.hardy_client(subdomain, username, password, :ssl => false)
7
+ harvest = Harvest.hardy_client(subdomain, username, password)
8
8
 
9
9
  # Print out all users, clients, and projects on the account
10
10
  puts "Users:"
@@ -6,7 +6,7 @@
6
6
  # username = 'yourusername'
7
7
  # password = 'yourpassword'
8
8
  #
9
- # api = Harvest.hardy_client(subdomain, username, password, :ssl => false)
9
+ # api = Harvest.hardy_client(subdomain, username, password)
10
10
  #
11
11
  # raise "Are you sure you want to do this? (comment out this exception if so)"
12
12
  #
@@ -4,7 +4,7 @@ subdomain = 'yoursubdomain'
4
4
  username = 'yourusername'
5
5
  password = 'yourpassword'
6
6
 
7
- harvest = Harvest.hardy_client(subdomain, username, password, :ssl => false)
7
+ harvest = Harvest.hardy_client(subdomain, username, password)
8
8
 
9
9
  # Create a Client add a Project to that Client
10
10
 
@@ -4,7 +4,7 @@ subdomain = 'yoursubdomain'
4
4
  username = 'userusername'
5
5
  password = 'yourpassword'
6
6
 
7
- harvest = Harvest.hardy_client(subdomain, username, password, :ssl => false)
7
+ harvest = Harvest.hardy_client(subdomain, username, password)
8
8
 
9
9
  # Create a Client, Project, and a User then assign that User to that Project
10
10
 
data/harvested.gemspec ADDED
@@ -0,0 +1,159 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{harvested}
8
+ s.version = "0.3.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Zach Moazeni"]
12
+ s.date = %q{2010-10-14}
13
+ s.description = %q{Harvested wraps the Harvest API concisely without the use of Rails dependencies. More information about the Harvest API can be found on their website (http://www.getharvest.com/api). For support hit up the Mailing List (http://groups.google.com/group/harvested)}
14
+ s.email = %q{zach.moazeni@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README.md"
17
+ ]
18
+ s.files = [
19
+ ".document",
20
+ ".gitignore",
21
+ "HISTORY",
22
+ "MIT-LICENSE",
23
+ "README.md",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "examples/basics.rb",
27
+ "examples/clear_account.rb",
28
+ "examples/task_assignments.rb",
29
+ "examples/user_assignments.rb",
30
+ "features/account.feature",
31
+ "features/client_contacts.feature",
32
+ "features/clients.feature",
33
+ "features/errors.feature",
34
+ "features/expense_categories.feature",
35
+ "features/expenses.feature",
36
+ "features/hardy_client.feature",
37
+ "features/projects.feature",
38
+ "features/reporting.feature",
39
+ "features/step_definitions/account_steps.rb",
40
+ "features/step_definitions/assignment_steps.rb",
41
+ "features/step_definitions/contact_steps.rb",
42
+ "features/step_definitions/debug_steps.rb",
43
+ "features/step_definitions/error_steps.rb",
44
+ "features/step_definitions/expenses_steps.rb",
45
+ "features/step_definitions/harvest_steps.rb",
46
+ "features/step_definitions/model_steps.rb",
47
+ "features/step_definitions/people_steps.rb",
48
+ "features/step_definitions/report_steps.rb",
49
+ "features/step_definitions/time_entry_steps.rb",
50
+ "features/support/env.rb",
51
+ "features/support/error_helpers.rb",
52
+ "features/support/fixtures/empty_clients.xml",
53
+ "features/support/fixtures/over_limit.xml",
54
+ "features/support/fixtures/receipt.png",
55
+ "features/support/fixtures/under_limit.xml",
56
+ "features/support/harvest_credentials.example.yml",
57
+ "features/support/harvest_helpers.rb",
58
+ "features/support/inflections.rb",
59
+ "features/task_assignment.feature",
60
+ "features/tasks.feature",
61
+ "features/time_tracking.feature",
62
+ "features/user_assignments.feature",
63
+ "features/users.feature",
64
+ "harvested.gemspec",
65
+ "lib/harvest/api/account.rb",
66
+ "lib/harvest/api/base.rb",
67
+ "lib/harvest/api/clients.rb",
68
+ "lib/harvest/api/contacts.rb",
69
+ "lib/harvest/api/expense_categories.rb",
70
+ "lib/harvest/api/expenses.rb",
71
+ "lib/harvest/api/projects.rb",
72
+ "lib/harvest/api/reports.rb",
73
+ "lib/harvest/api/task_assignments.rb",
74
+ "lib/harvest/api/tasks.rb",
75
+ "lib/harvest/api/time.rb",
76
+ "lib/harvest/api/user_assignments.rb",
77
+ "lib/harvest/api/users.rb",
78
+ "lib/harvest/base.rb",
79
+ "lib/harvest/base_model.rb",
80
+ "lib/harvest/behavior/activatable.rb",
81
+ "lib/harvest/behavior/crud.rb",
82
+ "lib/harvest/client.rb",
83
+ "lib/harvest/contact.rb",
84
+ "lib/harvest/credentials.rb",
85
+ "lib/harvest/errors.rb",
86
+ "lib/harvest/expense.rb",
87
+ "lib/harvest/expense_category.rb",
88
+ "lib/harvest/hardy_client.rb",
89
+ "lib/harvest/project.rb",
90
+ "lib/harvest/rate_limit_status.rb",
91
+ "lib/harvest/task.rb",
92
+ "lib/harvest/task_assignment.rb",
93
+ "lib/harvest/time_entry.rb",
94
+ "lib/harvest/timezones.rb",
95
+ "lib/harvest/user.rb",
96
+ "lib/harvest/user_assignment.rb",
97
+ "lib/harvested.rb",
98
+ "spec/harvest/base_spec.rb",
99
+ "spec/harvest/credentials_spec.rb",
100
+ "spec/harvest/expense_spec.rb",
101
+ "spec/harvest/task_assignment_spec.rb",
102
+ "spec/harvest/time_entry_spec.rb",
103
+ "spec/harvest/user_assignment_spec.rb",
104
+ "spec/harvest/user_spec.rb",
105
+ "spec/spec.default.opts",
106
+ "spec/spec_helper.rb"
107
+ ]
108
+ s.homepage = %q{http://github.com/zmoazeni/harvested}
109
+ s.rdoc_options = ["--charset=UTF-8"]
110
+ s.require_paths = ["lib"]
111
+ s.rubygems_version = %q{1.3.7}
112
+ s.summary = %q{A Ruby Wrapper for the Harvest API http://www.getharvest.com/}
113
+ s.test_files = [
114
+ "spec/harvest/base_spec.rb",
115
+ "spec/harvest/credentials_spec.rb",
116
+ "spec/harvest/expense_spec.rb",
117
+ "spec/harvest/task_assignment_spec.rb",
118
+ "spec/harvest/time_entry_spec.rb",
119
+ "spec/harvest/user_assignment_spec.rb",
120
+ "spec/harvest/user_spec.rb",
121
+ "spec/spec_helper.rb",
122
+ "examples/basics.rb",
123
+ "examples/clear_account.rb",
124
+ "examples/task_assignments.rb",
125
+ "examples/user_assignments.rb"
126
+ ]
127
+
128
+ if s.respond_to? :specification_version then
129
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
130
+ s.specification_version = 3
131
+
132
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
133
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
134
+ s.add_development_dependency(%q<cucumber>, [">= 0"])
135
+ s.add_development_dependency(%q<ruby-debug>, [">= 0"])
136
+ s.add_development_dependency(%q<fakeweb>, [">= 0"])
137
+ s.add_runtime_dependency(%q<httparty>, [">= 0"])
138
+ s.add_runtime_dependency(%q<happymapper>, [">= 0"])
139
+ s.add_runtime_dependency(%q<builder>, [">= 0"])
140
+ else
141
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
142
+ s.add_dependency(%q<cucumber>, [">= 0"])
143
+ s.add_dependency(%q<ruby-debug>, [">= 0"])
144
+ s.add_dependency(%q<fakeweb>, [">= 0"])
145
+ s.add_dependency(%q<httparty>, [">= 0"])
146
+ s.add_dependency(%q<happymapper>, [">= 0"])
147
+ s.add_dependency(%q<builder>, [">= 0"])
148
+ end
149
+ else
150
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
151
+ s.add_dependency(%q<cucumber>, [">= 0"])
152
+ s.add_dependency(%q<ruby-debug>, [">= 0"])
153
+ s.add_dependency(%q<fakeweb>, [">= 0"])
154
+ s.add_dependency(%q<httparty>, [">= 0"])
155
+ s.add_dependency(%q<happymapper>, [">= 0"])
156
+ s.add_dependency(%q<builder>, [">= 0"])
157
+ end
158
+ end
159
+
@@ -1,6 +1,11 @@
1
1
  module Harvest
2
2
  module API
3
+
4
+ # API Methods to contain all account actions
3
5
  class Account < Base
6
+
7
+ # Returns the current rate limit information
8
+ # @return [Harvest::RateLimitStatus]
4
9
  def rate_limit_status
5
10
  response = request(:get, credentials, '/account/rate_limit_status')
6
11
  Harvest::RateLimitStatus.parse(response.body)
@@ -2,11 +2,11 @@ module Harvest
2
2
  module API
3
3
  class Base
4
4
  attr_reader :credentials
5
-
5
+
6
6
  def initialize(credentials)
7
7
  @credentials = credentials
8
8
  end
9
-
9
+
10
10
  class << self
11
11
  def api_model(klass)
12
12
  class_eval <<-END
@@ -16,7 +16,7 @@ module Harvest
16
16
  END
17
17
  end
18
18
  end
19
-
19
+
20
20
  protected
21
21
  def request(method, credentials, path, options = {})
22
22
  response = HTTParty.send(method, "#{credentials.host}#{path}", :query => options[:query], :body => options[:body], :headers => {"Accept" => "application/xml", "Content-Type" => "application/xml; charset=utf-8", "Authorization" => "Basic #{credentials.basic_auth}", "User-Agent" => "Harvestable/#{Harvest::VERSION}"}.update(options[:headers] || {}), :format => :plain)
@@ -2,7 +2,7 @@ module Harvest
2
2
  module API
3
3
  class Clients < Base
4
4
  api_model Harvest::Client
5
-
5
+
6
6
  include Harvest::Behavior::Crud
7
7
  include Harvest::Behavior::Activatable
8
8
  end
@@ -11,7 +11,7 @@ module Harvest
11
11
  else
12
12
  request(:get, credentials, "/contacts")
13
13
  end
14
-
14
+
15
15
  api_model.parse(response.body)
16
16
  end
17
17
  end
@@ -5,12 +5,23 @@ module Harvest
5
5
 
6
6
  include Harvest::Behavior::Crud
7
7
 
8
+ # Creates and Assigns a task to the project
9
+ #
10
+ # == Examples
11
+ # project = harvest.projects.find(401)
12
+ # harvest.projects.create_task(project, 'Bottling Glue') # creates and assigns a task to the project
13
+ #
14
+ # @return [Harvest::Project]
8
15
  def create_task(project, task_name)
9
16
  response = request(:post, credentials, "/projects/#{project.to_i}/task_assignments/add_with_create_new_task", :body => task_xml(task_name))
10
17
  id = response.headers["location"].first.match(/\/.*\/(\d+)\/.*\/(\d+)/)[1]
11
18
  find(id)
12
19
  end
13
20
 
21
+ # Deactivates the project. Does nothing if the project is already deactivated
22
+ #
23
+ # @param [Harvest::Project] project the project you want to deactivate
24
+ # @return [Harvest::Project] the deactivated project
14
25
  def deactivate(project)
15
26
  if project.active?
16
27
  request(:put, credentials, "#{api_model.api_path}/#{project.to_i}/toggle", :headers => {'Content-Length' => '0'})
@@ -18,7 +29,11 @@ module Harvest
18
29
  end
19
30
  project
20
31
  end
21
-
32
+
33
+ # Activates the project. Does nothing if the project is already activated
34
+ #
35
+ # @param [Harvest::Project] project the project you want to activate
36
+ # @return [Harvest::Project] the activated project
22
37
  def activate(project)
23
38
  if !project.active?
24
39
  request(:put, credentials, "#{api_model.api_path}/#{project.to_i}/toggle", :headers => {'Content-Length' => '0'})
@@ -5,7 +5,13 @@ module Harvest
5
5
 
6
6
  include Harvest::Behavior::Crud
7
7
  include Harvest::Behavior::Activatable
8
-
8
+
9
+ # Triggers Harvest to reset the user's password and sends them an email to change it.
10
+ # @overload reset_password(id)
11
+ # @param [Integer] id the id of the user you want to reset the password for
12
+ # @overload reset_password(user)
13
+ # @param [Harvest::User] user the user you want to reset the password for
14
+ # @return [Harvest::User] the user you passed in
9
15
  def reset_password(user)
10
16
  request(:post, credentials, "#{api_model.api_path}/#{user.to_i}/reset_password")
11
17
  user
data/lib/harvest/base.rb CHANGED
@@ -2,48 +2,247 @@ module Harvest
2
2
  class Base
3
3
  attr_reader :request, :credentials
4
4
 
5
+ # @see Harvest.client
6
+ # @see Harvest.hardy_client
5
7
  def initialize(subdomain, username, password, options = {})
6
8
  options[:ssl] = true if options[:ssl].nil?
7
9
  @credentials = Credentials.new(subdomain, username, password, options[:ssl])
8
10
  raise InvalidCredentials unless credentials.valid?
9
11
  end
10
12
 
13
+ # All API actions surrounding accounts
14
+ #
15
+ # == Examples
16
+ # harvest.account.rate_limit_status # Returns a Harvest::RateLimitStatus
17
+ #
18
+ # @return [Harvest::API::Account]
11
19
  def account
12
20
  @account ||= Harvest::API::Account.new(credentials)
13
21
  end
14
22
 
23
+ # All API Actions surrounding Clients
24
+ #
25
+ # == Examples
26
+ # harvest.clients.all() # Returns all clients in the system
27
+ #
28
+ # harvest.clients.find(100) # Returns the client with id = 100
29
+ #
30
+ # client = Harvest::Client.new(:name => 'SuprCorp')
31
+ # saved_client = harvest.clients.create(client) # returns a saved version of Harvest::Client
32
+ #
33
+ # client = harvest.clients.find(205)
34
+ # client.name = 'SuprCorp LTD.'
35
+ # updated_client = harvest.clients.update(client) # returns an updated version of Harvest::Client
36
+ #
37
+ # client = harvest.clients.find(205)
38
+ # harvest.clients.delete(client) # returns 205
39
+ #
40
+ # client = harvest.clients.find(301)
41
+ # deactivated_client = harvest.clients.deactivate(client) # returns an updated deactivated client
42
+ # activated_client = harvest.clients.activate(client) # returns an updated activated client
43
+ #
44
+ # @see Harvest::Behavior::Crud
45
+ # @see Harvest::Behavior::Activatable
46
+ # @return [Harvest::API::Clients]
15
47
  def clients
16
48
  @clients ||= Harvest::API::Clients.new(credentials)
17
49
  end
18
50
 
51
+ # All API Actions surrounding Client Contacts
52
+ #
53
+ # == Examples
54
+ # harvest.contacts.all() # Returns all contacts in the system
55
+ # harvest.contacts.all(10) # Returns all contacts for the client id=10 in the system
56
+ #
57
+ # harvest.contacts.find(100) # Returns the contact with id = 100
58
+ #
59
+ # contact = Harvest::Contact.new(:first_name => 'Jane', :last_name => 'Doe', :client_id => 10)
60
+ # saved_contact = harvest.contacts.create(contact) # returns a saved version of Harvest::Contact
61
+ #
62
+ # contact = harvest.contacts.find(205)
63
+ # contact.first_name = 'Jilly'
64
+ # updated_contact = harvest.contacts.update(contact) # returns an updated version of Harvest::Contact
65
+ #
66
+ # contact = harvest.contacts.find(205)
67
+ # harvest.contacts.delete(contact) # returns 205
68
+ #
69
+ # @see Harvest::Behavior::Crud
70
+ # @return [Harvest::API::Contacts]
19
71
  def contacts
20
72
  @contacts ||= Harvest::API::Contacts.new(credentials)
21
73
  end
22
74
 
75
+ # All API Actions surrounding Projects
76
+ #
77
+ # == Examples
78
+ # harvest.projects.all() # Returns all projects in the system
79
+ #
80
+ # harvest.projects.find(100) # Returns the project with id = 100
81
+ #
82
+ # project = Harvest::Project.new(:name => 'SuprGlu' :client_id => 10)
83
+ # saved_project = harvest.projects.create(project) # returns a saved version of Harvest::Project
84
+ #
85
+ # project = harvest.projects.find(205)
86
+ # project.name = 'SuprSticky'
87
+ # updated_project = harvest.projects.update(project) # returns an updated version of Harvest::Project
88
+ #
89
+ # project = harvest.project.find(205)
90
+ # harvest.projects.delete(project) # returns 205
91
+ #
92
+ # project = harvest.projects.find(301)
93
+ # deactivated_project = harvest.projects.deactivate(project) # returns an updated deactivated project
94
+ # activated_project = harvest.projects.activate(project) # returns an updated activated project
95
+ #
96
+ # project = harvest.projects.find(401)
97
+ # harvest.projects.create_task(project, 'Bottling Glue') # creates and assigns a task to the project
98
+ #
99
+ # @see Harvest::Behavior::Crud
100
+ # @see Harvest::Behavior::Activatable
101
+ # @return [Harvest::API::Projects]
23
102
  def projects
24
103
  @projects ||= Harvest::API::Projects.new(credentials)
25
104
  end
26
105
 
106
+ # All API Actions surrounding Tasks
107
+ #
108
+ # == Examples
109
+ # harvest.tasks.all() # Returns all tasks in the system
110
+ #
111
+ # harvest.tasks.find(100) # Returns the task with id = 100
112
+ #
113
+ # task = Harvest::Task.new(:name => 'Server Administration' :default => true)
114
+ # saved_task = harvest.tasks.create(task) # returns a saved version of Harvest::Task
115
+ #
116
+ # task = harvest.tasks.find(205)
117
+ # task.name = 'Server Administration'
118
+ # updated_task = harvest.tasks.update(task) # returns an updated version of Harvest::Task
119
+ #
120
+ # task = harvest.task.find(205)
121
+ # harvest.tasks.delete(task) # returns 205
122
+ #
123
+ # @see Harvest::Behavior::Crud
124
+ # @return [Harvest::API::Tasks]
27
125
  def tasks
28
126
  @tasks ||= Harvest::API::Tasks.new(credentials)
29
127
  end
30
128
 
129
+ # All API Actions surrounding Users
130
+ #
131
+ # == Examples
132
+ # harvest.users.all() # Returns all users in the system
133
+ #
134
+ # harvest.users.find(100) # Returns the user with id = 100
135
+ #
136
+ # user = Harvest::User.new(:first_name => 'Edgar', :last_name => 'Ruth', :email => 'edgar@ruth.com', :password => 'mypassword', :password_confirmation => 'mypassword', :timezone => :cst, :admin => false, :telephone => '444-4444')
137
+ # saved_user = harvest.users.create(user) # returns a saved version of Harvest::User
138
+ #
139
+ # user = harvest.users.find(205)
140
+ # user.email = 'edgar@ruth.com'
141
+ # updated_user = harvest.users.update(user) # returns an updated version of Harvest::User
142
+ #
143
+ # user = harvest.users.find(205)
144
+ # harvest.users.delete(user) # returns 205
145
+ #
146
+ # user = harvest.users.find(301)
147
+ # deactivated_user = harvest.users.deactivate(user) # returns an updated deactivated user
148
+ # activated_user = harvest.users.activate(user) # returns an updated activated user
149
+ #
150
+ # user = harvest.users.find(401)
151
+ # harvest.users.reset_password(user) # will trigger the reset password feature of harvest and shoot the user an email
152
+ #
153
+ # @see Harvest::Behavior::Crud
154
+ # @see Harvest::Behavior::Activatable
155
+ # @return [Harvest::API::Users]
31
156
  def users
32
157
  @users ||= Harvest::API::Users.new(credentials)
33
158
  end
34
159
 
160
+ # All API Actions surrounding assigning tasks to projects
161
+ #
162
+ # == Examples
163
+ # project = harvest.projects.find(101)
164
+ # harvest.task_assignments.all(project) # returns all tasks assigned to the project (as Harvest::TaskAssignment)
165
+ #
166
+ # project = harvest.projects.find(201)
167
+ # harvest.task_assignments.find(project, 5) # returns the task assignment with ID 5 that is assigned to the project
168
+ #
169
+ # project = harvest.projects.find(301)
170
+ # task = harvest.tasks.find(100)
171
+ # assignment = Harvest::TaskAssignment.new(:task_id => task.id, :project_id => project.id)
172
+ # saved_assignment = harvest.task_assignments.create(assignment) # returns a saved version of the task assignment
173
+ #
174
+ # project = harvest.projects.find(401)
175
+ # assignment = harvest.task_assignments.find(project, 15)
176
+ # assignment.hourly_rate = 150
177
+ # updated_assignment = harvest.task_assignments.update(assignment) # returns an updated assignment
178
+ #
179
+ # project = harvest.projects.find(501)
180
+ # assignment = harvest.task_assignments.find(project, 25)
181
+ # harvest.task_assignments.delete(assignment) # returns 25
182
+ #
183
+ # @return [Harvest::API::TaskAssignments]
35
184
  def task_assignments
36
185
  @task_assignments ||= Harvest::API::TaskAssignments.new(credentials)
37
186
  end
38
187
 
188
+ # All API Actions surrounding assigning users to projects
189
+ #
190
+ # == Examples
191
+ # project = harvest.projects.find(101)
192
+ # harvest.user_assignments.all(project) # returns all users assigned to the project (as Harvest::UserAssignment)
193
+ #
194
+ # project = harvest.projects.find(201)
195
+ # harvest.user_assignments.find(project, 5) # returns the user assignment with ID 5 that is assigned to the project
196
+ #
197
+ # project = harvest.projects.find(301)
198
+ # user = harvest.users.find(100)
199
+ # assignment = Harvest::UserAssignment.new(:user_id => user.id, :project_id => project.id)
200
+ # saved_assignment = harvest.user_assignments.create(assignment) # returns a saved version of the user assignment
201
+ #
202
+ # project = harvest.projects.find(401)
203
+ # assignment = harvest.user_assignments.find(project, 15)
204
+ # assignment.project_manager = true
205
+ # updated_assignment = harvest.user_assignments.update(assignment) # returns an updated assignment
206
+ #
207
+ # project = harvest.projects.find(501)
208
+ # assignment = harvest.user_assignments.find(project, 25)
209
+ # harvest.user_assignments.delete(assignment) # returns 25
210
+ #
211
+ # @return [Harvest::API::UserAssignments]
39
212
  def user_assignments
40
213
  @user_assignments ||= Harvest::API::UserAssignments.new(credentials)
41
214
  end
42
215
 
216
+ # All API Actions surrounding managing expense categories
217
+ #
218
+ # == Examples
219
+ # harvest.expense_categories.all() # Returns all expense categories in the system
220
+ #
221
+ # harvest.expense_categories.find(100) # Returns the expense category with id = 100
222
+ #
223
+ # category = Harvest::ExpenseCategory.new(:name => 'Mileage', :unit_price => 0.485)
224
+ # saved_category = harvest.expense_categories.create(category) # returns a saved version of Harvest::ExpenseCategory
225
+ #
226
+ # category = harvest.clients.find(205)
227
+ # category.name = 'Travel'
228
+ # updated_category = harvest.expense_categories.update(category) # returns an updated version of Harvest::ExpenseCategory
229
+ #
230
+ # category = harvest.expense_categories.find(205)
231
+ # harvest.expense_categories.delete(category) # returns 205
232
+ #
233
+ # @see Harvest::Behavior::Crud
234
+ # @return [Harvest::API::ExpenseCategories]
43
235
  def expense_categories
44
236
  @expense_categories ||= Harvest::API::ExpenseCategories.new(credentials)
45
237
  end
46
238
 
239
+ # All API Actions surrounding expenses
240
+ #
241
+ # == Examples
242
+ # harvest.expenses.all() # Returns all expenses for the current week
243
+ # harvest.expenses.all(Time.parse('11/12/2009')) # returns all expenses for the week of 11/12/2009
244
+ #
245
+ # harvest.expenses.find(100) # Returns the expense with id = 100
47
246
  def expenses
48
247
  @expenses ||= Harvest::API::Expenses.new(credentials)
49
248
  end
@@ -1,21 +1,58 @@
1
1
  module Harvest
2
+ # The parent class of all Harvest models. Contains useful inheritable methods
2
3
  class BaseModel
4
+
5
+ # Initializes the model. You can pass the attributes as a hash in a ActiveRecord-like style
6
+ #
7
+ # == Examples
8
+ # client = Harvest::Client.new(:name => 'John Doe')
9
+ # client.name # returns 'John Doe'
3
10
  def initialize(attributes = {})
4
11
  self.attributes = attributes
5
12
  end
6
-
13
+
14
+ # Given a hash, sets the corresponding attributes
15
+ #
16
+ # == Examples
17
+ # client = Harvest::Client.new(:name => 'John Doe')
18
+ # client.name # returns 'John Doe'
19
+ # client.attributes = {:name => 'Terry Vaughn'}
20
+ # client.name # returns 'Terry Vaughn'
21
+ #
22
+ # @return [void]
7
23
  def attributes=(attributes)
8
24
  attributes.each {|k,v| send("#{k}=", v)}
9
25
  end
10
-
26
+
27
+ # Checks the equality of another model based on the id
28
+ #
29
+ # == Examples
30
+ # client1 = Harvest::Client.new(:id => 1)
31
+ # client2 = Harvest::Client.new(:id => 1)
32
+ # client3 = Harvest::Client.new(:id => 2)
33
+ #
34
+ # client1 == client2 # returns true
35
+ # client1 == client3 # returns false
36
+ #
37
+ # @return [Boolean]
11
38
  def ==(other)
12
39
  id == other.id
13
40
  end
14
-
41
+
42
+ # Returns the id of the model
43
+ #
44
+ # == Examples
45
+ # client = Harvest::Client.new(:id => 1)
46
+ # client.to_i # returns 1
47
+ #
48
+ # @return [Fixnum]
15
49
  def to_i
16
50
  id
17
51
  end
18
-
52
+
53
+ # Builds the XML of the model. Primarily used to interact with the Harvest API.
54
+ #
55
+ # @return [String]
19
56
  def to_xml
20
57
  builder = Builder::XmlMarkup.new
21
58
  builder.tag!(self.class.tag_name) do |c|
@@ -26,6 +63,8 @@ module Harvest
26
63
  end
27
64
 
28
65
  class << self
66
+ # This sets the API path so the API collections can use them in an agnostic way
67
+ # @return [void]
29
68
  def api_path(path = nil)
30
69
  @path ||= path
31
70
  end
@@ -1,6 +1,12 @@
1
1
  module Harvest
2
2
  module Behavior
3
+
4
+ # Activate/Deactivate behaviors that can be brought into API collections
3
5
  module Activatable
6
+ # Deactivates the item. Does nothing if the item is already deactivated
7
+ #
8
+ # @param [Harvest::BaseModel] model the model you want to deactivate
9
+ # @return [Harvest::BaseModel] the deactivated model
4
10
  def deactivate(model)
5
11
  if model.active?
6
12
  request(:post, credentials, "#{api_model.api_path}/#{model.to_i}/toggle")
@@ -8,7 +14,11 @@ module Harvest
8
14
  end
9
15
  model
10
16
  end
11
-
17
+
18
+ # Activates the item. Does nothing if the item is already activated
19
+ #
20
+ # @param [Harvest::BaseModel] model the model you want to activate
21
+ # @return [Harvest::BaseModel] the activated model
12
22
  def activate(model)
13
23
  if !model.active?
14
24
  request(:post, credentials, "#{api_model.api_path}/#{model.to_i}/toggle")
@@ -1,30 +1,56 @@
1
1
  module Harvest
2
2
  module Behavior
3
3
  module Crud
4
+ # Retrieves all items
5
+ # @return [Array<Harvest::BaseModel>] an array of models depending on where you're calling it from (e.g. [Harvest::Client] from Harvest::Base#clients)
4
6
  def all
5
7
  response = request(:get, credentials, api_model.api_path)
6
8
  api_model.parse(response.body)
7
9
  end
8
10
 
11
+ # Retrieves an item by id
12
+ # @overload find(id)
13
+ # @param [Integer] the id of the item you want to retreive
14
+ # @overload find(id)
15
+ # @param [String] id the String version of the id
16
+ # @overload find(model)
17
+ # @param [Harvest::BaseModel] id you can pass a model and it will return a refreshed version
18
+ #
19
+ # @return [Harvest::BaseModel] the model depends on where you're calling it from (e.g. Harvest::Client from Harvest::Base#clients)
9
20
  def find(id)
10
21
  response = request(:get, credentials, "#{api_model.api_path}/#{id}")
11
22
  api_model.parse(response.body, :single => true)
12
23
  end
13
24
 
25
+ # Creates an item
26
+ # @param [Harvest::BaseModel] model the item you want to create
27
+ # @return [Harvest::BaseModel] the created model depending on where you're calling it from (e.g. Harvest::Client from Harvest::Base#clients)
14
28
  def create(model)
15
29
  response = request(:post, credentials, "#{api_model.api_path}", :body => model.to_xml)
16
30
  id = response.headers["location"].first.match(/\/.*\/(\d+)/)[1]
17
31
  find(id)
18
32
  end
19
33
 
34
+ # Updates an item
35
+ # @param [Harvest::BaseModel] model the model you want to update
36
+ # @return [Harvest::BaseModel] the created model depending on where you're calling it from (e.g. Harvest::Client from Harvest::Base#clients)
20
37
  def update(model)
21
38
  request(:put, credentials, "#{api_model.api_path}/#{model.to_i}", :body => model.to_xml)
22
39
  find(model.id)
23
40
  end
24
41
 
42
+ # Deletes an item
43
+ # @overload delete(model)
44
+ # @param [Harvest::BaseModel] model the item you want to delete
45
+ # @overload delete(id)
46
+ # @param [Integer] id the id of the item you want to delete
47
+ # @overload delete(id)
48
+ # @param [String] id the String version of the id of the item you want to delete
49
+ #
50
+ # @return [Integer] the id of the item deleted
25
51
  def delete(model)
26
52
  request(:delete, credentials, "#{api_model.api_path}/#{model.to_i}")
27
- model.id
53
+ model.to_i
28
54
  end
29
55
  end
30
56
  end
@@ -1,4 +1,15 @@
1
1
  module Harvest
2
+ # The model that contains information about a client
3
+ #
4
+ # == Fields
5
+ # [+id+] (READONLY) the id of the client
6
+ # [+name+] (REQUIRED) the name of the client
7
+ # [+details+] the details of the client
8
+ # [+currency+] what type of currency is associated with the client
9
+ # [+currency_symbol+] what currency symbol is associated with the client
10
+ # [+active?+] true|false on whether the client is active
11
+ # [+highrise_id+] (READONLY) the highrise id associated with this client
12
+ # [+update_at+] (READONLY) the last modification timestamp
2
13
  class Client < BaseModel
3
14
  include HappyMapper
4
15
 
@@ -12,7 +23,8 @@ module Harvest
12
23
  element :currency_symbol, String, :tag => "currency-symbol"
13
24
  element :cache_version, Integer, :tag => "cache-version"
14
25
  element :updated_at, Time, :tag => "updated-at"
15
-
26
+ element :highrise_id, Integer, :tag => 'highrise-id'
27
+
16
28
  alias_method :active?, :active
17
29
  end
18
30
  end
@@ -1,4 +1,16 @@
1
1
  module Harvest
2
+ # The model that contains information about a client contact
3
+ #
4
+ # == Fields
5
+ # [+id+] (READONLY) the id of the contact
6
+ # [+client_id+] (REQUIRED) the id of the client this contact is associated with
7
+ # [+first_name+] (REQUIRED) the first name of the contact
8
+ # [+last_name+] (REQUIRED) the last name of the contact
9
+ # [+email+] the email of the contact
10
+ # [+title+] the title of the contact
11
+ # [+phone_office+] the office phone number of the contact
12
+ # [+phone_moble+] the moble phone number of the contact
13
+ # [+fax+] the fax number of the contact
2
14
  class Contact < BaseModel
3
15
  include HappyMapper
4
16
 
@@ -12,5 +24,6 @@ module Harvest
12
24
  element :phone_office, String, :tag => "phone-office"
13
25
  element :phone_mobile, String, :tag => "phone-mobile"
14
26
  element :fax, String
27
+ element :title, String
15
28
  end
16
29
  end
@@ -1,4 +1,27 @@
1
1
  module Harvest
2
+
3
+ # The model that contains information about a project
4
+ #
5
+ # == Fields
6
+ # [+id+] (READONLY) the id of the project
7
+ # [+name+] (REQUIRED) the name of the project
8
+ # [+client_id+] (REQUIRED) the client id of the project
9
+ # [+code+] the project code
10
+ # [+notes+] the project notes
11
+ # [+active?+] true|false whether the project is active
12
+ # [+billable?+] true|false where the project is billable
13
+ # [+budget_by+] how the budget is calculated for the project +project|project_cost|task|person|nil+
14
+ # [+budget+] what the budget is for the project (based on budget_by)
15
+ # [+bill_by+] how to bill the project +Tasks|People|Project|nil+
16
+ # [+hourly_rate+] what the hourly rate for the project is based on +bill_by+
17
+ # [+notify_when_over_budget?+] whether the project will send notifications when it goes over budget
18
+ # [+over_budget_notification_percentage+] what percentage of the budget the project has to be before it sends a notification. Based on +notify_when_over_budget?+
19
+ # [+show_budget_to_all?+] whether the project's budget is shown to employees and contractors
20
+ # [+basecamp_id+] (READONLY) the id of the basecamp project associated to the project
21
+ # [+highrise_deal_id+] (READONLY) the id of the highrise deal associated to the project
22
+ # [+active_task_assignments_count+] (READONLY) the number of active task assignments
23
+ # [+created_at+] (READONLY) when the project was created
24
+ # [+updated_at+] (READONLY) when the project was updated
2
25
  class Project < BaseModel
3
26
  include HappyMapper
4
27
 
@@ -12,11 +35,22 @@ module Harvest
12
35
  element :fees, String
13
36
  element :active, Boolean
14
37
  element :billable, Boolean
15
- element :budget, String
16
- element :budget_by, Float, :tag => 'budget-by'
38
+ element :budget, Float
39
+ element :budget_by, String, :tag => 'budget-by'
17
40
  element :hourly_rate, Float, :tag => 'hourly-rate'
18
41
  element :bill_by, String, :tag => 'bill-by'
42
+ element :created_at, Time, :tag => 'created-at'
43
+ element :updated_at, Time, :tag => 'updated-at'
44
+ element :notify_when_over_budget, Boolean, :tag => 'notify-when-over-budget'
45
+ element :over_budget_notification_percentage, Float, :tag => 'over-budget-notification-percentage'
46
+ element :show_budget_to_all, Boolean, :tag => 'show-budget-to-all'
47
+ element :basecamp_id, Integer, :tag => 'basecamp-id'
48
+ element :highrise_deal_id, Integer, :tag => 'highrise-deal-id'
49
+ element :active_task_assignments_count, Integer, :tag => 'active-task-assignments-count'
19
50
 
20
51
  alias_method :active?, :active
52
+ alias_method :billable?, :billable
53
+ alias_method :notify_when_over_budget?, :notify_when_over_budget
54
+ alias_method :show_budget_to_all?, :show_budget_to_all
21
55
  end
22
56
  end
@@ -1,4 +1,13 @@
1
1
  module Harvest
2
+
3
+ # The model that contains the information about the user's rate limit
4
+ #
5
+ # == Fields
6
+ # [+last_access_at+] The last registered request
7
+ # [+count+] The current number of requests registered
8
+ # [+timeframe_limit+] The amount of seconds before a rate limit refresh occurs
9
+ # [+max_calls+] The number of requests you can make within the +timeframe_limit+
10
+ # [+lockout_seconds+] If you exceed the rate limit, how long you will be locked out from Harvest
2
11
  class RateLimitStatus < BaseModel
3
12
  include HappyMapper
4
13
 
@@ -9,6 +18,9 @@ module Harvest
9
18
  element :max_calls, Integer, :tag => 'max-calls'
10
19
  element :lockout_seconds, Integer, :tag => 'lockout-seconds'
11
20
 
21
+ # Returns true if the user is over their rate limit
22
+ # @return [Boolean]
23
+ # @see http://www.getharvest.com/api
12
24
  def over_limit?
13
25
  count > max_calls
14
26
  end
data/lib/harvest/task.rb CHANGED
@@ -1,4 +1,14 @@
1
1
  module Harvest
2
+
3
+ # The model that contains information about a task
4
+ #
5
+ # == Fields
6
+ # [+id+] (READONLY) the id of the task
7
+ # [+name+] (REQUIRED) the name of the task
8
+ # [+billable+] whether the task is billable by default
9
+ # [+deactivated+] whether the task is deactivated
10
+ # [+hourly_rate+] what the default hourly rate for the task is
11
+ # [+default?+] whether to add this task to new projects by default
2
12
  class Task < BaseModel
3
13
  include HappyMapper
4
14
 
@@ -1,6 +1,5 @@
1
- # shamelessly ripped from Rails: http://github.com/rails/rails/blob/master/activesupport/lib/active_support/values/time_zone.rb
2
-
3
1
  module Harvest
2
+ # shamelessly ripped from Rails: http://github.com/rails/rails/blob/master/activesupport/lib/active_support/values/time_zone.rb
4
3
  module Timezones
5
4
  MAPPING = {
6
5
  "pacific/midway" => "International Date Line West",
data/lib/harvest/user.rb CHANGED
@@ -1,7 +1,24 @@
1
1
  module Harvest
2
+
3
+ # The model that contains information about a task
4
+ #
5
+ # == Fields
6
+ # [+id+] (READONLY) the id of the user
7
+ # [+email+] the email of the user
8
+ # [+first_name+] the first name for the user
9
+ # [+last_name+] the last name for the user
10
+ # [+telephone+] the telephone for the user
11
+ # [+department] the department for the user
12
+ # [+password|password_confirmation+] the password for the user (only used on create.)
13
+ # [+has_access_to_all_future_projects+] whether the user should be added to future projects by default
14
+ # [+hourly_rate+] what the default hourly rate for the user is
15
+ # [+admin?+] whether the user is an admin
16
+ # [+contractor?+] whether the user is a contractor
17
+ # [+contractor?+] whether the user is a contractor
18
+ # [+timezone+] the timezone for the user.
2
19
  class User < BaseModel
3
20
  include HappyMapper
4
-
21
+
5
22
  api_path '/people'
6
23
  element :id, Integer
7
24
  element :email, String
@@ -13,14 +30,23 @@ module Harvest
13
30
  element :admin, Boolean, :tag => 'is-admin'
14
31
  element :contractor, Boolean, :tag => 'is-contractor'
15
32
  element :telephone, String
33
+ element :department, String
16
34
  element :timezone, String
17
35
  element :password, String
18
36
  element :password_confirmation, String, :tag => 'password-confirmation'
19
-
37
+
20
38
  alias_method :active?, :active
21
39
  alias_method :admin?, :admin
22
40
  alias_method :contractor?, :contractor
23
-
41
+
42
+ # Sets the timezone for the user. This can be done in a variety of ways.
43
+ #
44
+ # == Examples
45
+ # user.timezone = :cst # the easiest way. CST, EST, MST, and PST are supported
46
+ #
47
+ # user.timezone = 'america/chicago' # a little more verbose
48
+ #
49
+ # user.timezone = 'Central Time (US & Canada)' # the most explicit way
24
50
  def timezone=(timezone)
25
51
  tz = timezone.to_s.downcase
26
52
  case tz
data/lib/harvested.rb CHANGED
@@ -16,13 +16,44 @@ require 'harvest/base'
16
16
  %w(base account clients contacts projects tasks users task_assignments user_assignments expense_categories expenses time reports).each {|a| require "harvest/api/#{a}"}
17
17
 
18
18
  module Harvest
19
- VERSION = "0.3.0".freeze
19
+ VERSION = "0.3.1".freeze
20
20
 
21
21
  class << self
22
+
23
+ # Creates a standard client that will raise all errors it encounters
24
+ #
25
+ # == Options
26
+ # * +:ssl+ - Whether or not to use SSL when connecting to Harvest. This is dependent on whether your account supports it. Set to +true+ by default
27
+ # == Examples
28
+ # Harvest.client('mysubdomain', 'myusername', 'mypassword', :ssl => false)
29
+ #
30
+ # @return [Harvest::Base]
22
31
  def client(subdomain, username, password, options = {})
23
32
  Harvest::Base.new(subdomain, username, password, options)
24
33
  end
25
34
 
35
+ # Creates a hardy client that will retry common HTTP errors it encounters and sleep() if it determines it is over your rate limit
36
+ #
37
+ # == Options
38
+ # * +:ssl+ - Whether or not to use SSL when connecting to Harvest. This is dependent on whether your account supports it. Set to +true+ by default
39
+ # * +:retry+ - How many times the hardy client should retry errors. Set to +5+ by default.
40
+ #
41
+ # == Examples
42
+ # Harvest.hardy_client('mysubdomain', 'myusername', 'mypassword', :ssl => true, :retry => 3)
43
+ #
44
+ # == Errors
45
+ # The hardy client will retry the following errors
46
+ # * Harvest::Unavailable
47
+ # * Harvest::InformHarvest
48
+ # * Net::HTTPError
49
+ # * Net::HTTPFatalError
50
+ # * Errno::ECONNRESET
51
+ #
52
+ # == Rate Limits
53
+ # The hardy client will make as many requests as it can until it detects it has gone over the rate limit. Then it will +sleep()+ for the how ever long it takes for the limit to reset. You can find more information about the Rate Limiting at http://www.getharvest.com/api
54
+ #
55
+ # @return [Harvest::HardyClient] a Harvest::Base wrapped in a Harvest::HardyClient
56
+ # @see Harvest::Base
26
57
  def hardy_client(subdomain, username, password, options = {})
27
58
  retries = options.delete(:retry)
28
59
  Harvest::HardyClient.new(client(subdomain, username, password, options), (retries || 5))
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  $LOAD_PATH.unshift(File.dirname(__FILE__))
2
2
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
3
  require "rubygems"
4
- require 'harvest'
4
+ require 'harvested'
5
5
  require 'spec'
6
6
  require 'spec/autorun'
7
7
 
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: harvested
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 17
4
5
  prerelease: false
5
6
  segments:
6
7
  - 0
7
8
  - 3
8
- - 0
9
- version: 0.3.0
9
+ - 1
10
+ version: 0.3.1
10
11
  platform: ruby
11
12
  authors:
12
13
  - Zach Moazeni
@@ -14,16 +15,18 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-04-11 00:00:00 -04:00
18
+ date: 2010-10-14 00:00:00 -04:00
18
19
  default_executable:
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
21
22
  name: rspec
22
23
  prerelease: false
23
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
24
26
  requirements:
25
27
  - - ">="
26
28
  - !ruby/object:Gem::Version
29
+ hash: 13
27
30
  segments:
28
31
  - 1
29
32
  - 2
@@ -35,9 +38,11 @@ dependencies:
35
38
  name: cucumber
36
39
  prerelease: false
37
40
  requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
38
42
  requirements:
39
43
  - - ">="
40
44
  - !ruby/object:Gem::Version
45
+ hash: 3
41
46
  segments:
42
47
  - 0
43
48
  version: "0"
@@ -47,9 +52,11 @@ dependencies:
47
52
  name: ruby-debug
48
53
  prerelease: false
49
54
  requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
50
56
  requirements:
51
57
  - - ">="
52
58
  - !ruby/object:Gem::Version
59
+ hash: 3
53
60
  segments:
54
61
  - 0
55
62
  version: "0"
@@ -59,9 +66,11 @@ dependencies:
59
66
  name: fakeweb
60
67
  prerelease: false
61
68
  requirement: &id004 !ruby/object:Gem::Requirement
69
+ none: false
62
70
  requirements:
63
71
  - - ">="
64
72
  - !ruby/object:Gem::Version
73
+ hash: 3
65
74
  segments:
66
75
  - 0
67
76
  version: "0"
@@ -71,9 +80,11 @@ dependencies:
71
80
  name: httparty
72
81
  prerelease: false
73
82
  requirement: &id005 !ruby/object:Gem::Requirement
83
+ none: false
74
84
  requirements:
75
85
  - - ">="
76
86
  - !ruby/object:Gem::Version
87
+ hash: 3
77
88
  segments:
78
89
  - 0
79
90
  version: "0"
@@ -83,9 +94,11 @@ dependencies:
83
94
  name: happymapper
84
95
  prerelease: false
85
96
  requirement: &id006 !ruby/object:Gem::Requirement
97
+ none: false
86
98
  requirements:
87
99
  - - ">="
88
100
  - !ruby/object:Gem::Version
101
+ hash: 3
89
102
  segments:
90
103
  - 0
91
104
  version: "0"
@@ -95,15 +108,17 @@ dependencies:
95
108
  name: builder
96
109
  prerelease: false
97
110
  requirement: &id007 !ruby/object:Gem::Requirement
111
+ none: false
98
112
  requirements:
99
113
  - - ">="
100
114
  - !ruby/object:Gem::Version
115
+ hash: 3
101
116
  segments:
102
117
  - 0
103
118
  version: "0"
104
119
  type: :runtime
105
120
  version_requirements: *id007
106
- description: Harvested wraps the Harvest API concisely without the use of Rails dependencies. More information about the Harvest API can be found at http://www.getharvest.com/api
121
+ description: Harvested wraps the Harvest API concisely without the use of Rails dependencies. More information about the Harvest API can be found on their website (http://www.getharvest.com/api). For support hit up the Mailing List (http://groups.google.com/group/harvested)
107
122
  email: zach.moazeni@gmail.com
108
123
  executables: []
109
124
 
@@ -112,6 +127,7 @@ extensions: []
112
127
  extra_rdoc_files:
113
128
  - README.md
114
129
  files:
130
+ - .document
115
131
  - .gitignore
116
132
  - HISTORY
117
133
  - MIT-LICENSE
@@ -156,6 +172,7 @@ files:
156
172
  - features/time_tracking.feature
157
173
  - features/user_assignments.feature
158
174
  - features/users.feature
175
+ - harvested.gemspec
159
176
  - lib/harvest/api/account.rb
160
177
  - lib/harvest/api/base.rb
161
178
  - lib/harvest/api/clients.rb
@@ -208,23 +225,27 @@ rdoc_options:
208
225
  require_paths:
209
226
  - lib
210
227
  required_ruby_version: !ruby/object:Gem::Requirement
228
+ none: false
211
229
  requirements:
212
230
  - - ">="
213
231
  - !ruby/object:Gem::Version
232
+ hash: 3
214
233
  segments:
215
234
  - 0
216
235
  version: "0"
217
236
  required_rubygems_version: !ruby/object:Gem::Requirement
237
+ none: false
218
238
  requirements:
219
239
  - - ">="
220
240
  - !ruby/object:Gem::Version
241
+ hash: 3
221
242
  segments:
222
243
  - 0
223
244
  version: "0"
224
245
  requirements: []
225
246
 
226
247
  rubyforge_project:
227
- rubygems_version: 1.3.6
248
+ rubygems_version: 1.3.7
228
249
  signing_key:
229
250
  specification_version: 3
230
251
  summary: A Ruby Wrapper for the Harvest API http://www.getharvest.com/