r_hapi 0.1.1 → 0.1.2

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