r_hapi 0.1.1 → 0.1.2

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.
@@ -10,6 +10,13 @@ RHapi is a Ruby wrapper for the HubSpot API (HAPI).
10
10
 
11
11
  == Using RHapi
12
12
 
13
+ Intsall
14
+ If you use RVM.
15
+ gem install r_hapi
16
+
17
+ If not you may need to do this:
18
+ sudo gem install r_hapi
19
+
13
20
  First configure RHapi to work with your Hubspot API Key.
14
21
 
15
22
  RHapi.configure do |config|
@@ -28,12 +35,33 @@ Then to get a list of leads.
28
35
 
29
36
  To find leads named Barny.
30
37
  leads = RHapi::Lead.find("Barny")
38
+
39
+ You can also pass additional options to the find method.
40
+ options = {
41
+ :sort => "lastName", # Possible sort values include: firstName, lastName, email, address, phone, insertedAt, lastConvertedAt, lastModifiedAt, closedAt
42
+ :dir => "asc", # Use desc for descending.
43
+ :max => 25, # Maximum value is 100
44
+ :offset => 50, # Used in combination with max for paging results.
45
+ :startTime => 1298721462000, # Expressed as milliseconds since epoch time. Returned list will have only leads inserted after this time. Default is 0 and returns all leads up to max.
46
+ :stopTime => 1298721462000, # Expressed as milliseconds since epoch time.
47
+ :timePivot => "insertedAt", # The field the start and stop times should be applied to in the search. Can be: insertedAt, firstConvertedAt, lastConvertedAt, lastModifiedAt, closedAt.
48
+ :excludeConversionEvents => false, # Used to exclude all items in the leadConversionEvents collection from the API results.
49
+ :optout => false, # Set to true to include only leads that have unsubscribed from lead nurturing. The default value, false, includes all leads.
50
+ :eligibleForEmail => false, # Set to true to include only leads eligible for email marketing.
51
+ :bounced => false, # Set to true to include only leads that HubSpot has tried to email, and the email bounced. The default value, false, includes all leads.
52
+ :notImported => false # Set to true to include only web leads. The default value, false, includes both imported and web leads.
53
+ }
54
+ leads = RHapi::Lead.find("Barny", options)
31
55
 
32
56
  To update a lead.
33
- lead = leads.fist
57
+ lead = leads.first
34
58
  lead.first_name = "Fred"
35
59
  lead.last_name = "Flintsone"
36
60
  lead.update
61
+
62
+ You can also pass a params hash to update a lead.
63
+ params = {:first_name => "Fred", :last_name => "Flintstone", :city => "Bedrock"}
64
+ lead.update(params)
37
65
 
38
66
  To get a single lead with a guid. Assumes the guid has be saved from a previous search.
39
67
  lead = RHapi::Lead.find_by_guid(lead.guid)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.1.2
@@ -1,6 +1,7 @@
1
1
  require File.expand_path('../r_hapi/lead', __FILE__)
2
2
  require File.expand_path('../r_hapi/configuration', __FILE__)
3
3
  require File.expand_path('../r_hapi/r_hapi_exception', __FILE__)
4
+
4
5
  require 'curb'
5
6
  require 'json'
6
7
 
@@ -0,0 +1,56 @@
1
+ require 'curb'
2
+ require 'json'
3
+ module RHapi
4
+ module Connection
5
+
6
+ # Instance methods ---------------------------------------------------------------------------
7
+
8
+ def put(url, payload)
9
+ data = payload.to_json
10
+ response = Curl::Easy.http_put(url, data) do |curl|
11
+ curl.headers["Content-Type"] = "application/json"
12
+ curl.on_failure do |response, err|
13
+ RHapi::ConnectionError.raise_error("#{response.response_code}\n Error is: #{err.inspect}")
14
+ end
15
+ end
16
+ RHapi::ConnectionError.raise_error(response.header_str) unless response.header_str =~ /2\d\d/
17
+ end
18
+
19
+ # Class methods -----------------------------------------------------------------------------
20
+
21
+ module ClassMethods
22
+
23
+ def url_for(method, id=nil, options={})
24
+ url = "#{RHapi.options[:end_point]}/leads/#{RHapi.options[:version]}/#{method}"
25
+ url << "/#{id}" unless id.nil?
26
+ url << "?hapikey=#{RHapi.options[:api_key]}"
27
+
28
+ raise(RHapi::UriError, "Options must be a hash in order to build the url.") unless options.is_a?(Hash)
29
+ url << append_options(options) unless options.empty?
30
+ url
31
+ end
32
+
33
+ def append_options(options)
34
+ query_string = ""
35
+ options.each do |key, value|
36
+ query_string << "&#{key.to_s}=#{value}"
37
+ end
38
+ query_string
39
+ end
40
+
41
+ def get(url)
42
+ response = Curl::Easy.perform(url) do |curl|
43
+ curl.on_failure do |response, err|
44
+ RHapi::ConnectionError.raise_error("#{response.response_code}\n Error is: #{err.inspect}")
45
+ end
46
+ end
47
+ RHapi::ConnectionError.raise_error( response.header_str) unless response.header_str =~ /2\d\d/
48
+ RHapi::ConnectionError.raise_error(response.body_str) if response.body_str =~ /Error/i
49
+ response
50
+ end
51
+
52
+ end # End class methods
53
+
54
+
55
+ end
56
+ end
@@ -1,9 +1,13 @@
1
1
  require 'rubygems'
2
2
  require 'active_support'
3
3
  require 'active_support/inflector/inflections'
4
+ require File.expand_path('../connection', __FILE__)
5
+
4
6
  module RHapi
5
7
 
6
8
  class Lead
9
+ include Connection
10
+ extend Connection::ClassMethods
7
11
 
8
12
  attr_accessor :attributes, :changed_attributes
9
13
 
@@ -18,11 +22,11 @@ module RHapi
18
22
  # An optional string value that is used to search several basic lead fields: first name, last name, email address,
19
23
  # and company name. According to HubSpot docs, a more advanced search is coming in the future.
20
24
  # The default value for is nil, meaning return all leads.
21
- def self.find(search=nil)
22
- url = "#{RHapi.options[:end_point]}/leads/#{RHapi.options[:version]}/list?hapikey=#{RHapi.options[:api_key]}&search=#{search}"
23
- data = Curl::Easy.perform(url)
24
- RHapi::RHapiException.raise_error(data.body_str) if data.body_str =~ /Error/i
25
- lead_data = JSON.parse(data.body_str)
25
+ def self.find(search=nil, options={})
26
+ options[:search] = search unless search.nil?
27
+ response = get(url_for("list", nil, options))
28
+
29
+ lead_data = JSON.parse(response.body_str)
26
30
  leads = []
27
31
  lead_data.each do |data|
28
32
  lead = Lead.new(data)
@@ -33,25 +37,28 @@ module RHapi
33
37
 
34
38
  # Finds specified lead by the guid.
35
39
  def self.find_by_guid(guid)
36
- url = "#{RHapi.options[:end_point]}/leads/#{RHapi.options[:version]}/lead/#{guid}?hapikey=#{RHapi.options[:api_key]}"
37
- c = Curl::Easy.perform(url)
38
- RHapi::RHapiException.raise_error(c.body_str) if c.body_str =~ /Error/i
39
- lead_data = JSON.parse(c.body_str)
40
+ response = get(url_for("lead", guid))
41
+ lead_data = JSON.parse(response.body_str)
40
42
  Lead.new(lead_data)
41
43
  end
42
44
 
43
45
  # Instance methods -------------------------------------------------------
44
- def update
45
- url = "#{RHapi.options[:end_point]}/leads/#{RHapi.options[:version]}/lead/#{self.guid}?hapikey=#{RHapi.options[:api_key]}"
46
- data = self.changed_attributes.to_json
47
- c = Curl::Easy.http_put(url, data) do |curl|
48
- curl.headers["Content-Type"] = "application/json"
49
- curl.header_in_body = true
50
- end
51
- RHapi::RHapiException.raise_error(c.body_str) unless c.body_str =~ /200/i
46
+ def update(params={})
47
+ update_attributes(params) unless params.empty?
48
+ response = put(Lead.url_for("lead", self.guid), self.changed_attributes)
52
49
  true
53
50
  end
54
51
 
52
+ def update_attributes(params)
53
+ raise(RHapi::AttributeError, "The params must be a hash.") unless params.is_a?(Hash)
54
+ params.each do |key, value|
55
+ attribute = ActiveSupport::Inflector.camelize(key.to_s, false)
56
+ raise(RHapi::AttributeError, "No Hubspot attribute with the name #{attribute}.") unless self.attributes.include?(attribute)
57
+ self.changed_attributes[attribute] = value
58
+ self.attributes[attribute] = value
59
+ end
60
+ end
61
+
55
62
 
56
63
 
57
64
  # Work with data in the data hash
@@ -1,5 +1,5 @@
1
1
  module RHapi
2
- class RHapiException < RuntimeError
2
+ class ConnectionError < StandardError
3
3
  attr :error_string
4
4
 
5
5
  def initialize(error_string)
@@ -8,21 +8,25 @@ module RHapi
8
8
 
9
9
  def message
10
10
  if @error_string =~ /401/
11
- "HubSopt returned a 401 error. Make sure your API key is correct."
11
+ "HubSopt returned a 401 error: #{error_string}"
12
12
  elsif @error_string =~ /404/
13
- "HubSopt returned a 404 error. Check the end point or the guid to make sure it is valid."
13
+ "HubSopt returned a 404 error: #{error_string}"
14
14
  elsif @error_string =~ /500/
15
- "HubSopt returned a 500 error."
15
+ "HubSopt returned a 500 error: #{error_string}"
16
16
  else
17
- # else send back the whole message.
18
17
  @error_string
19
18
  end
20
19
  end
21
20
 
22
- def self.raise_error(error_response)
23
- exception = RHapi::RHapiException.new(error_response)
21
+ def self.raise_error(response)
22
+ exception = RHapi::ConnectionError.new(response)
24
23
  raise(exception, exception.message)
25
- end
24
+ end
26
25
 
27
26
  end
27
+
28
+ class UriError < TypeError; end
29
+
30
+ class AttributeError < TypeError; end
31
+
28
32
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{r_hapi}
8
- s.version = "0.1.1"
8
+ s.version = "0.1.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Tim Stephenson of RaddOnline"]
12
- s.date = %q{2011-03-18}
12
+ s.date = %q{2011-03-22}
13
13
  s.description = %q{Makes it easy to use the HubSpot API in a Ruby application.}
14
14
  s.email = %q{tim@raddonline.com}
15
15
  s.extra_rdoc_files = [
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
25
25
  "VERSION",
26
26
  "lib/r_hapi.rb",
27
27
  "lib/r_hapi/configuration.rb",
28
+ "lib/r_hapi/connection.rb",
28
29
  "lib/r_hapi/lead.rb",
29
30
  "lib/r_hapi/r_hapi_exception.rb",
30
31
  "r_hapi.gemspec",
@@ -2,6 +2,34 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
3
  describe "RHapi::Lead" do
4
4
 
5
+ context "connection" do
6
+ before do
7
+ RHapi.configure do |config|
8
+ config.api_key = test_config["api_key"]
9
+ config.hub_spot_site = "http://mysite.hubspot.com"
10
+ end
11
+ @url = "https://hubapi.com/leads/v1/list?hapikey=#{test_config["api_key"]}"
12
+ end
13
+ it "should generate a url with a search param" do
14
+ url = RHapi::Lead.url_for("list", nil, {:search => "test"})
15
+ url.should == @url << "&search=test"
16
+ end
17
+ it "should generate a url with multiple params" do
18
+ url = RHapi::Lead.url_for("list", nil, {:search => "test", :sort => "firstName", :dir => "asc", :max => 10})
19
+ url.include?("&sort=firstName").should == true
20
+ url.include?("&search=test").should == true
21
+ url.include?("&dir=asc").should == true
22
+ url.include?("&max=10").should == true
23
+ end
24
+ it "should generate a url with an id" do
25
+ url = RHapi::Lead.url_for("lead", "myid")
26
+ url.should == "https://hubapi.com/leads/v1/lead/myid?hapikey=#{test_config["api_key"]}"
27
+ end
28
+ it "should raise a url error if options is not a hash" do
29
+ lambda {RHapi::Lead.url_for("list", nil, nil)}.should raise_error(RHapi::UriError)
30
+ end
31
+ end
32
+
5
33
  context "when searching for leads" do
6
34
  before do
7
35
  RHapi.configure do |config|
@@ -37,8 +65,7 @@ describe "RHapi::Lead" do
37
65
  lead.analytics_details.length.should == 12
38
66
  lead.analytics_details["allViewsImported"].should == true
39
67
  end
40
-
41
-
68
+
42
69
  end
43
70
 
44
71
  context "updating a lead" do
@@ -64,18 +91,32 @@ describe "RHapi::Lead" do
64
91
  stub_lead_update
65
92
  leads = RHapi::Lead.find
66
93
  lead = leads.first
67
- lead.first_name = "Barny"
68
- lead.last_name = "Rubble"
94
+ lead.first_name = "Adam"
95
+ lead.last_name = "Enbar"
69
96
  lead.update.should == true
70
97
  end
71
98
 
99
+ it "should have a list of changed attributes when updating with a params hash" do
100
+ stub_lead_update
101
+ leads = RHapi::Lead.find
102
+ lead = leads.first
103
+ lead.update({:first_name => "Wilma", :last_name => "Flintstone", :city => "Bedrock", :state => "CA"}).should == true
104
+ lead.changed_attributes.length.should == 4
105
+ lead.changed_attributes["firstName"].should == "Wilma"
106
+ lead.changed_attributes["firstName"].should == "Wilma"
107
+ lead.changed_attributes["city"].should == "Bedrock"
108
+ lead.changed_attributes["state"].should == "CA"
109
+ end
110
+
72
111
  it "should raise an error if 200 is not returned" do
73
- stub_lead_update_error
74
112
  leads = RHapi::Lead.find
75
113
  lead = leads.first
76
114
  lead.first_name = "Barny"
77
115
  lead.last_name = "Rubble"
78
- lambda {lead.update}.should raise_error(RHapi::RHapiException)
116
+ lead.guid = "wrong"
117
+ stub_lead_update_error
118
+
119
+ lambda {lead.update}.should raise_error(RHapi::ConnectionError)
79
120
  end
80
121
 
81
122
  end
@@ -97,9 +138,8 @@ describe "RHapi::Lead" do
97
138
  end
98
139
 
99
140
  it "should raise an error if an error string is returned" do
100
- leads = RHapi::Lead.find
101
141
  stub_leads_error
102
- lambda {RHapi::Lead.find_by_guid(leads.first.guid)}.should raise_error(RHapi::RHapiException)
142
+ lambda {RHapi::Lead.find_by_guid("badguid")}.should raise_error(RHapi::ConnectionError)
103
143
  end
104
144
  end
105
145
 
@@ -114,7 +154,7 @@ describe "RHapi::Lead" do
114
154
 
115
155
  it "should raise an exception" do
116
156
  stub_leads_error
117
- lambda {RHapi::Lead.find}.should raise_error(RHapi::RHapiException)
157
+ lambda {RHapi::Lead.find}.should raise_error(RHapi::ConnectionError)
118
158
  end
119
159
  end
120
160
 
@@ -29,31 +29,36 @@ def test_error
29
29
  end
30
30
 
31
31
  def stub_leads_search
32
- @data = mock("data")
33
- @data.stub!(:body_str).and_return(test_leads)
34
- Curl::Easy.stub!(:perform).and_return(@data)
32
+ @response = mock("response_data")
33
+ @response.stub!(:body_str).and_return(test_leads)
34
+ @response.stub!(:header_str).and_return("200 OK")
35
+ Curl::Easy.stub!(:perform).and_return(@response)
35
36
  end
36
37
 
37
38
  def stub_leads_find_by_guid
38
- @data = mock("data")
39
- @data.stub!(:body_str).and_return(test_lead)
40
- Curl::Easy.stub!(:perform).and_return(@data)
39
+ @response = mock("response_data")
40
+ @response.stub!(:body_str).and_return(test_lead)
41
+ @response.stub!(:header_str).and_return("200 OK")
42
+ Curl::Easy.stub!(:perform).and_return(@response)
41
43
  end
42
44
 
43
45
  def stub_leads_error
44
- @data = mock("data")
45
- @data.stub!(:body_str).and_return(test_error)
46
- Curl::Easy.stub!(:perform).and_return(@data)
46
+ @response = mock("response_data")
47
+ @response.stub!(:body_str).and_return(test_error)
48
+ @response.stub!(:header_str).and_return("404")
49
+ Curl::Easy.stub!(:perform).and_return(@response)
47
50
  end
48
51
 
49
52
  def stub_lead_update
50
53
  @response_mock = mock("data")
51
54
  @response_mock.stub!(:body_str).and_return("200 OK")
55
+ @response_mock.stub!(:header_str).and_return("200 OK")
52
56
  Curl::Easy.stub!(:http_put).and_return(@response_mock)
53
57
  end
54
58
 
55
59
  def stub_lead_update_error
56
60
  @response_mock = mock("data")
61
+ @response_mock.stub!(:header_str).and_return("500")
57
62
  @response_mock.stub!(:body_str).and_return("Error: 500 internal server error.")
58
63
  Curl::Easy.stub!(:http_put).and_return(@response_mock)
59
64
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: r_hapi
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 31
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 1
10
- version: 0.1.1
9
+ - 2
10
+ version: 0.1.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Tim Stephenson of RaddOnline
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-03-18 00:00:00 -07:00
18
+ date: 2011-03-22 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -190,6 +190,7 @@ files:
190
190
  - VERSION
191
191
  - lib/r_hapi.rb
192
192
  - lib/r_hapi/configuration.rb
193
+ - lib/r_hapi/connection.rb
193
194
  - lib/r_hapi/lead.rb
194
195
  - lib/r_hapi/r_hapi_exception.rb
195
196
  - r_hapi.gemspec