njones-marketo 1.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/marketo/authentication_header.rb +48 -0
- data/lib/marketo/client.rb +202 -0
- data/lib/marketo/enums.rb +23 -0
- data/lib/marketo/lead_key.rb +31 -0
- data/lib/marketo/lead_record.rb +59 -0
- data/lib/njones-marketo.rb +16 -0
- data/spec/marketo/authentication_header_spec.rb +66 -0
- data/spec/marketo/client_spec.rb +372 -0
- data/spec/marketo/lead_key_spec.rb +40 -0
- data/spec/marketo/lead_record_spec.rb +86 -0
- metadata +101 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
module Rapleaf
|
2
|
+
module Marketo
|
3
|
+
# This class exists only to encapsulate the authentication header part of a soap request to marketo
|
4
|
+
# Marketo requires a somewhat complex calculation of an encrypted signature and so it seemed sensible to pull this code out here
|
5
|
+
class AuthenticationHeader
|
6
|
+
DIGEST = OpenSSL::Digest::Digest.new('sha1')
|
7
|
+
|
8
|
+
def initialize(access_key, secret_key, time = DateTime.now)
|
9
|
+
@access_key = access_key
|
10
|
+
@secret_key = secret_key
|
11
|
+
@time = time
|
12
|
+
end
|
13
|
+
|
14
|
+
public
|
15
|
+
# time should be a DateTime instance
|
16
|
+
def set_time(time)
|
17
|
+
@time = time
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_mktows_user_id
|
21
|
+
@access_key
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_request_signature
|
25
|
+
calculate_signature
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_request_timestamp
|
29
|
+
@time.to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_hash
|
33
|
+
{
|
34
|
+
"mktowsUserId" => get_mktows_user_id,
|
35
|
+
"requestSignature" => get_request_signature,
|
36
|
+
"requestTimestamp" => get_request_timestamp
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def calculate_signature
|
42
|
+
request_timestamp = get_request_timestamp
|
43
|
+
string_to_encrypt = request_timestamp + @access_key
|
44
|
+
OpenSSL::HMAC.hexdigest(DIGEST, @secret_key, string_to_encrypt)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,202 @@
|
|
1
|
+
require File.expand_path('authentication_header', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
module Rapleaf
|
4
|
+
module Marketo
|
5
|
+
|
6
|
+
def self.new_client(access_key, secret_key, api_version='1.7', api_subdomain='na-c')
|
7
|
+
|
8
|
+
api_version = api_version.sub(".", "_")
|
9
|
+
client = Savon::Client.new do
|
10
|
+
wsdl.endpoint = "https://#{api_subdomain}.marketo.com/soap/mktows/#{api_version}"
|
11
|
+
wsdl.document = "http://app.marketo.com/soap/mktows/#{api_version}?WSDL"
|
12
|
+
http.read_timeout = 90
|
13
|
+
http.open_timeout = 90
|
14
|
+
http.headers = {"Connection" => "Keep-Alive"}
|
15
|
+
end
|
16
|
+
|
17
|
+
Client.new(client, Rapleaf::Marketo::AuthenticationHeader.new(access_key, secret_key))
|
18
|
+
end
|
19
|
+
|
20
|
+
# = The client for talking to marketo
|
21
|
+
# based on the SOAP wsdl file: <i>http://app.marketo.com/soap/mktows/1_4?WSDL</i>
|
22
|
+
#
|
23
|
+
# Usage:
|
24
|
+
#
|
25
|
+
# client = Rapleaf::Marketo.new_client(<access_key>, <secret_key>)
|
26
|
+
#
|
27
|
+
# == get_lead_by_email:
|
28
|
+
#
|
29
|
+
# lead_record = client.get_lead_by_email('sombody@examnple.com')
|
30
|
+
#
|
31
|
+
# puts lead_record.idnum
|
32
|
+
#
|
33
|
+
# puts lead_record.get_attribute('FirstName')
|
34
|
+
#
|
35
|
+
# puts lead_record.get_attribute('LastName')
|
36
|
+
#
|
37
|
+
# == sync_lead: (update)
|
38
|
+
#
|
39
|
+
# lead_record = client.sync_lead('example@rapleaf.com', 'Joe', 'Smith', 'Company 1', '415 911')
|
40
|
+
#
|
41
|
+
# == sync_lead_record: (update with custom fields)
|
42
|
+
#
|
43
|
+
# lead_record = Rapleaf::Marketo::LeadRecord.new('harry@rapleaf.com')
|
44
|
+
#
|
45
|
+
# lead_record.set_attribute('FirstName', 'harry')
|
46
|
+
#
|
47
|
+
# lead_record.set_attribute('LastName', 'smith')
|
48
|
+
#
|
49
|
+
# lead_record.set_attribute('Email', 'harry@somesite.com')
|
50
|
+
#
|
51
|
+
# lead_record.set_attribute('Company', 'Rapleaf')
|
52
|
+
#
|
53
|
+
# lead_record.set_attribute('MobilePhone', '123 456')
|
54
|
+
#
|
55
|
+
# response = client.sync_lead_record(lead_record)
|
56
|
+
class Client
|
57
|
+
# This constructor is used internally, create your client with *Rapleaf::Marketo.new_client(<access_key>, <secret_key>)*
|
58
|
+
def initialize(savon_client, authentication_header)
|
59
|
+
@client = savon_client
|
60
|
+
@header = authentication_header
|
61
|
+
end
|
62
|
+
|
63
|
+
public
|
64
|
+
|
65
|
+
def get_lead_by_idnum(idnum)
|
66
|
+
get_lead(LeadKey.new(LeadKeyType::IDNUM, idnum))
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
def get_lead_by_email(email)
|
71
|
+
get_lead(LeadKey.new(LeadKeyType::EMAIL, email))
|
72
|
+
end
|
73
|
+
|
74
|
+
def set_logger(logger)
|
75
|
+
@logger = logger
|
76
|
+
end
|
77
|
+
|
78
|
+
# create (if new) or update (if existing) a lead
|
79
|
+
#
|
80
|
+
# * email - email address of lead
|
81
|
+
# * first - first name of lead
|
82
|
+
# * last - surname/last name of lead
|
83
|
+
# * company - company the lead is associated with
|
84
|
+
# * mobile - mobile/cell phone number
|
85
|
+
#
|
86
|
+
# returns the LeadRecord instance on success otherwise nil
|
87
|
+
def sync_lead(email, first, last, company, mobile)
|
88
|
+
lead_record = LeadRecord.new(email)
|
89
|
+
lead_record.set_attribute('FirstName', first)
|
90
|
+
lead_record.set_attribute('LastName', last)
|
91
|
+
lead_record.set_attribute('Email', email)
|
92
|
+
lead_record.set_attribute('Company', company)
|
93
|
+
lead_record.set_attribute('MobilePhone', mobile)
|
94
|
+
sync_lead_record(lead_record)
|
95
|
+
end
|
96
|
+
|
97
|
+
def sync_lead_record(lead_record)
|
98
|
+
begin
|
99
|
+
attributes = []
|
100
|
+
lead_record.each_attribute_pair do |name, value|
|
101
|
+
attributes << {:attr_name => name, :attr_type => 'string', :attr_value => value}
|
102
|
+
end
|
103
|
+
|
104
|
+
response = send_request("ns1:paramsSyncLead", {
|
105
|
+
:return_lead => true,
|
106
|
+
:lead_record =>
|
107
|
+
{:email => lead_record.email,
|
108
|
+
:lead_attribute_list => {
|
109
|
+
:attribute => attributes}}})
|
110
|
+
return LeadRecord.from_hash(response[:success_sync_lead][:result][:lead_record])
|
111
|
+
rescue Exception => e
|
112
|
+
@logger.log(e) if @logger
|
113
|
+
return nil
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def sync_multi_lead_records(lead_records)
|
118
|
+
send_records = []
|
119
|
+
begin
|
120
|
+
lead_records.each do |lead_record|
|
121
|
+
attributes = []
|
122
|
+
lead_record.each_attribute_pair do |name, value|
|
123
|
+
attributes << {:attr_name => name, :attr_type => 'string', :attr_value => value}
|
124
|
+
end
|
125
|
+
|
126
|
+
send_records << {:lead_record =>
|
127
|
+
{ "Email" => lead_record.email,
|
128
|
+
:lead_attribute_list =>
|
129
|
+
{ :attribute => attributes }
|
130
|
+
}
|
131
|
+
}
|
132
|
+
end
|
133
|
+
|
134
|
+
response = send_request("ns1:paramsSyncMultipleLeads", {
|
135
|
+
:lead_record_list => send_records }) # an array of lead records
|
136
|
+
|
137
|
+
return response
|
138
|
+
rescue Exception => e
|
139
|
+
@logger.log(e) if @logger
|
140
|
+
return @client.http
|
141
|
+
#return nil
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def add_to_list(list_key, email)
|
146
|
+
list_operation(list_key, ListOperationType::ADD_TO, email)
|
147
|
+
end
|
148
|
+
|
149
|
+
def remove_from_list(list_key, email)
|
150
|
+
list_operation(list_key, ListOperationType::REMOVE_FROM, email)
|
151
|
+
end
|
152
|
+
|
153
|
+
def is_member_of_list?(list_key, email)
|
154
|
+
list_operation(list_key, ListOperationType::IS_MEMBER_OF, email)
|
155
|
+
end
|
156
|
+
|
157
|
+
private
|
158
|
+
def list_operation(list_key, list_operation_type, email)
|
159
|
+
begin
|
160
|
+
response = send_request("ns1:paramsListOperation", {
|
161
|
+
:list_operation => list_operation_type,
|
162
|
+
:list_key => list_key,
|
163
|
+
:strict => 'false',
|
164
|
+
:list_member_list => {
|
165
|
+
:lead_key => [
|
166
|
+
{:key_type => 'EMAIL', :key_value => email}
|
167
|
+
]
|
168
|
+
}
|
169
|
+
})
|
170
|
+
return response
|
171
|
+
rescue Exception => e
|
172
|
+
@logger.log(e) if @logger
|
173
|
+
return nil
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def get_lead(lead_key)
|
178
|
+
begin
|
179
|
+
response = send_request("ns1:paramsGetLead", {:lead_key => lead_key.to_hash})
|
180
|
+
return LeadRecord.from_hash(response[:success_get_lead][:result][:lead_record_list][:lead_record])
|
181
|
+
rescue Exception => e
|
182
|
+
@logger.log(e) if @logger
|
183
|
+
return nil
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def send_request(namespace, body)
|
188
|
+
@header.set_time(DateTime.now)
|
189
|
+
response = request(namespace, body, @header.to_hash)
|
190
|
+
response.to_hash
|
191
|
+
end
|
192
|
+
|
193
|
+
def request(namespace, body, header)
|
194
|
+
@client.request namespace do |soap|
|
195
|
+
soap.namespaces["xmlns:ns1"] = "http://www.marketo.com/mktows/"
|
196
|
+
soap.body = body
|
197
|
+
soap.header["ns1:AuthenticationHeader"] = header
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Rapleaf
|
2
|
+
module Marketo
|
3
|
+
# Types of operations you can do on a marketo list
|
4
|
+
module ListOperationType
|
5
|
+
ADD_TO = 'ADDTOLIST'
|
6
|
+
REMOVE_FROM = 'REMOVEFROMLIST'
|
7
|
+
IS_MEMBER_OF = 'ISMEMBEROFLIST'
|
8
|
+
end
|
9
|
+
|
10
|
+
# Types of keys that can be used to look up a lead
|
11
|
+
module LeadKeyType
|
12
|
+
IDNUM = "IDNUM"
|
13
|
+
COOKIE = "COOKIE"
|
14
|
+
EMAIL = "EMAIL"
|
15
|
+
LEADOWNEREMAIL = "LEADOWNEREMAIL"
|
16
|
+
SFDCACCOUNTID = "SFDCACCOUNTID"
|
17
|
+
SFDCCONTACTID = "SFDCCONTACTID"
|
18
|
+
SFDCLEADID = "SFDCLEADID"
|
19
|
+
SFDCLEADOWNERID = "SFDCLEADOWNERID"
|
20
|
+
SFDCOPPTYID = "SFDCOPPTYID"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Rapleaf
|
2
|
+
module Marketo
|
3
|
+
# Encapsulates a key used to look up or describe a specific marketo lead.
|
4
|
+
class LeadKey
|
5
|
+
# - *key_type* the type of key to use see LeadKeyType
|
6
|
+
# - *key_value* normally a string value for the given type
|
7
|
+
def initialize(key_type, key_value)
|
8
|
+
@key_type = key_type
|
9
|
+
@key_value = key_value
|
10
|
+
end
|
11
|
+
|
12
|
+
# get the key type
|
13
|
+
def key_type
|
14
|
+
@key_type
|
15
|
+
end
|
16
|
+
|
17
|
+
# get the key value
|
18
|
+
def key_value
|
19
|
+
@key_value
|
20
|
+
end
|
21
|
+
|
22
|
+
# create a hash from this instance, for sending this object to marketo using savon
|
23
|
+
def to_hash
|
24
|
+
{
|
25
|
+
:key_type => @key_type,
|
26
|
+
:key_value => @key_value
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Rapleaf
|
2
|
+
module Marketo
|
3
|
+
# Represents a record of the data known about a lead within marketo
|
4
|
+
class LeadRecord
|
5
|
+
def initialize(email, idnum = nil)
|
6
|
+
@email = email
|
7
|
+
@idnum = idnum
|
8
|
+
@attributes = {}
|
9
|
+
set_attribute('Email', @email)
|
10
|
+
end
|
11
|
+
|
12
|
+
# hydrates an instance from a savon hash returned form the marketo API
|
13
|
+
def self.from_hash(savon_hash)
|
14
|
+
lead_record = LeadRecord.new(savon_hash[:email], savon_hash[:id].to_i)
|
15
|
+
savon_hash[:lead_attribute_list][:attribute].each do |attribute|
|
16
|
+
lead_record.set_attribute(attribute[:attr_name], attribute[:attr_value])
|
17
|
+
end
|
18
|
+
lead_record
|
19
|
+
end
|
20
|
+
|
21
|
+
# get the record idnum
|
22
|
+
def idnum
|
23
|
+
@idnum
|
24
|
+
end
|
25
|
+
|
26
|
+
# get the record email
|
27
|
+
def email
|
28
|
+
@email
|
29
|
+
end
|
30
|
+
|
31
|
+
def attributes
|
32
|
+
@attributes
|
33
|
+
end
|
34
|
+
|
35
|
+
# update the value of the named attribute
|
36
|
+
def set_attribute(name, value)
|
37
|
+
@attributes[name] = value
|
38
|
+
end
|
39
|
+
|
40
|
+
# get the value for the named attribute
|
41
|
+
def get_attribute(name)
|
42
|
+
@attributes[name]
|
43
|
+
end
|
44
|
+
|
45
|
+
# will yield pairs of |attribute_name, attribute_value|
|
46
|
+
def each_attribute_pair(&block)
|
47
|
+
@attributes.each_pair do |name, value|
|
48
|
+
block.call(name, value)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def ==(other)
|
53
|
+
@attributes == other.attributes &&
|
54
|
+
@idnum == other.idnum &&
|
55
|
+
@email == other.email
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'savon'
|
3
|
+
|
4
|
+
Savon.configure do |config|
|
5
|
+
config.log = false # disable logging
|
6
|
+
end
|
7
|
+
|
8
|
+
require File.expand_path('marketo/client', File.dirname(__FILE__))
|
9
|
+
require File.expand_path('marketo/authentication_header', File.dirname(__FILE__))
|
10
|
+
require File.expand_path('marketo/enums', File.dirname(__FILE__))
|
11
|
+
require File.expand_path('marketo/lead_key', File.dirname(__FILE__))
|
12
|
+
require File.expand_path('marketo/lead_record', File.dirname(__FILE__))
|
13
|
+
|
14
|
+
|
15
|
+
|
16
|
+
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
module Rapleaf
|
4
|
+
module Marketo
|
5
|
+
ACCESS_KEY = 'ACCESS_KEY'
|
6
|
+
SECRET_KEY = 'SECRET_KEY'
|
7
|
+
|
8
|
+
describe AuthenticationHeader do
|
9
|
+
it "should set mktowsUserId to access key" do
|
10
|
+
header = Rapleaf::Marketo::AuthenticationHeader.new(ACCESS_KEY, SECRET_KEY)
|
11
|
+
header.get_mktows_user_id.should == ACCESS_KEY
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should set requestSignature" do
|
15
|
+
header = Rapleaf::Marketo::AuthenticationHeader.new(ACCESS_KEY, SECRET_KEY)
|
16
|
+
header.get_request_signature.should_not be_nil
|
17
|
+
header.get_request_signature.should_not == ''
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should set requestTimestamp in correct format" do
|
21
|
+
header = Rapleaf::Marketo::AuthenticationHeader.new(ACCESS_KEY, SECRET_KEY)
|
22
|
+
time = DateTime.new(1998, 1, 17, 20, 15, 1)
|
23
|
+
header.set_time(time)
|
24
|
+
header.get_request_timestamp().should == '1998-01-17T20:15:01+00:00'
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should calculate encrypted signature" do
|
28
|
+
# I got this example of the marketo API docs
|
29
|
+
|
30
|
+
access_key = 'bigcorp1_461839624B16E06BA2D663'
|
31
|
+
secret_key = '899756834129871744AAEE88DDCC77CDEEDEC1AAAD66'
|
32
|
+
|
33
|
+
header = Rapleaf::Marketo::AuthenticationHeader.new(access_key, secret_key)
|
34
|
+
header.set_time(DateTime.new(2010, 4, 9, 14, 4, 55, -7/24.0))
|
35
|
+
|
36
|
+
header.get_request_timestamp.should == '2010-04-09T14:04:54-07:00'
|
37
|
+
header.get_request_signature.should == 'ffbff4d4bef354807481e66dc7540f7890523a87'
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should cope if no date is given" do
|
41
|
+
header = Rapleaf::Marketo::AuthenticationHeader.new(ACCESS_KEY, SECRET_KEY)
|
42
|
+
expected = DateTime.now
|
43
|
+
actual = DateTime.parse(header.get_request_timestamp)
|
44
|
+
|
45
|
+
expected.year.should == actual.year
|
46
|
+
expected.hour.should == actual.hour
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should to_hash correctly" do
|
50
|
+
# I got this example from the marketo API docs
|
51
|
+
|
52
|
+
access_key = 'bigcorp1_461839624B16E06BA2D663'
|
53
|
+
secret_key = '899756834129871744AAEE88DDCC77CDEEDEC1AAAD66'
|
54
|
+
|
55
|
+
header = Rapleaf::Marketo::AuthenticationHeader.new(access_key, secret_key)
|
56
|
+
header.set_time(DateTime.new(2010, 4, 9, 14, 4, 55, -7/24.0))
|
57
|
+
|
58
|
+
header.to_hash.should == {
|
59
|
+
'mktowsUserId' => header.get_mktows_user_id,
|
60
|
+
'requestSignature' => header.get_request_signature,
|
61
|
+
'requestTimestamp' => header.get_request_timestamp,
|
62
|
+
}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,372 @@
|
|
1
|
+
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
module Rapleaf
|
4
|
+
module Marketo
|
5
|
+
|
6
|
+
describe Client do
|
7
|
+
EMAIL = "some@email.com"
|
8
|
+
IDNUM = 29
|
9
|
+
FIRST = 'Joe'
|
10
|
+
LAST = 'Smith'
|
11
|
+
COMPANY = 'Rapleaf'
|
12
|
+
MOBILE = '415 123 456'
|
13
|
+
API_KEY = 'API123KEY'
|
14
|
+
|
15
|
+
context 'Exception handling' do
|
16
|
+
it "should return nil if any exception is raised on get_lead request" do
|
17
|
+
savon_client = mock('savon_client').as_null_object
|
18
|
+
authentication_header = mock('authentication_header').as_null_object
|
19
|
+
client = Rapleaf::Marketo::Client.new(savon_client, authentication_header)
|
20
|
+
savon_client.should_receive(:request).and_raise Exception
|
21
|
+
client.get_lead_by_email(EMAIL).should be_nil
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should return nil if any exception is raised on sync_lead request" do
|
25
|
+
savon_client = mock('savon_client').as_null_object
|
26
|
+
authentication_header = mock('authentication_header').as_null_object
|
27
|
+
client = Rapleaf::Marketo::Client.new(savon_client, authentication_header)
|
28
|
+
savon_client.should_receive(:request).and_raise Exception
|
29
|
+
client.sync_lead(EMAIL, FIRST, LAST, COMPANY, MOBILE).should be_nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'Client interaction' do
|
34
|
+
it "should have the correct body format on get_lead_by_idnum" do
|
35
|
+
savon_client = mock('savon_client')
|
36
|
+
authentication_header = mock('authentication_header')
|
37
|
+
client = Rapleaf::Marketo::Client.new(savon_client, authentication_header)
|
38
|
+
response_hash = {
|
39
|
+
:success_get_lead => {
|
40
|
+
:result => {
|
41
|
+
:count => 1,
|
42
|
+
:lead_record_list => {
|
43
|
+
:lead_record => {
|
44
|
+
:email => EMAIL,
|
45
|
+
:lead_attribute_list => {
|
46
|
+
:attribute => [
|
47
|
+
{:attr_name => 'name1', :attr_type => 'string', :attr_value => 'val1'},
|
48
|
+
{:attr_name => 'name2', :attr_type => 'string', :attr_value => 'val2'},
|
49
|
+
{:attr_name => 'name3', :attr_type => 'string', :attr_value => 'val3'},
|
50
|
+
{:attr_name => 'name4', :attr_type => 'string', :attr_value => 'val4'}
|
51
|
+
]
|
52
|
+
},
|
53
|
+
:foreign_sys_type => nil,
|
54
|
+
:foreign_sys_person_id => nil,
|
55
|
+
:id => IDNUM.to_s
|
56
|
+
}
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
61
|
+
expect_request(savon_client,
|
62
|
+
authentication_header,
|
63
|
+
equals_matcher(:lead_key => {
|
64
|
+
:key_value => IDNUM,
|
65
|
+
:key_type => LeadKeyType::IDNUM
|
66
|
+
}),
|
67
|
+
'ns1:paramsGetLead',
|
68
|
+
response_hash)
|
69
|
+
expected_lead_record = LeadRecord.new(EMAIL, IDNUM)
|
70
|
+
expected_lead_record.set_attribute('name1', 'val1')
|
71
|
+
expected_lead_record.set_attribute('name2', 'val2')
|
72
|
+
expected_lead_record.set_attribute('name3', 'val3')
|
73
|
+
expected_lead_record.set_attribute('name4', 'val4')
|
74
|
+
client.get_lead_by_idnum(IDNUM).should == expected_lead_record
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should have the correct body format on get_lead_by_email" do
|
78
|
+
savon_client = mock('savon_client')
|
79
|
+
authentication_header = mock('authentication_header')
|
80
|
+
client = Rapleaf::Marketo::Client.new(savon_client, authentication_header)
|
81
|
+
response_hash = {
|
82
|
+
:success_get_lead => {
|
83
|
+
:result => {
|
84
|
+
:count => 1,
|
85
|
+
:lead_record_list => {
|
86
|
+
:lead_record => {
|
87
|
+
:email => EMAIL,
|
88
|
+
:lead_attribute_list => {
|
89
|
+
:attribute => [
|
90
|
+
{:attr_name => 'name1', :attr_type => 'string', :attr_value => 'val1'},
|
91
|
+
{:attr_name => 'name2', :attr_type => 'string', :attr_value => 'val2'},
|
92
|
+
{:attr_name => 'name3', :attr_type => 'string', :attr_value => 'val3'},
|
93
|
+
{:attr_name => 'name4', :attr_type => 'string', :attr_value => 'val4'}
|
94
|
+
]
|
95
|
+
},
|
96
|
+
:foreign_sys_type => nil,
|
97
|
+
:foreign_sys_person_id => nil,
|
98
|
+
:id => IDNUM.to_s
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}
|
102
|
+
}
|
103
|
+
}
|
104
|
+
expect_request(savon_client,
|
105
|
+
authentication_header,
|
106
|
+
equals_matcher({:lead_key => {
|
107
|
+
:key_value => EMAIL,
|
108
|
+
:key_type => LeadKeyType::EMAIL}}),
|
109
|
+
'ns1:paramsGetLead',
|
110
|
+
response_hash)
|
111
|
+
expected_lead_record = LeadRecord.new(EMAIL, IDNUM)
|
112
|
+
expected_lead_record.set_attribute('name1', 'val1')
|
113
|
+
expected_lead_record.set_attribute('name2', 'val2')
|
114
|
+
expected_lead_record.set_attribute('name3', 'val3')
|
115
|
+
expected_lead_record.set_attribute('name4', 'val4')
|
116
|
+
client.get_lead_by_email(EMAIL).should == expected_lead_record
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should have the correct body format on sync_lead_record" do
|
120
|
+
savon_client = mock('savon_client')
|
121
|
+
authentication_header = mock('authentication_header')
|
122
|
+
client = Rapleaf::Marketo::Client.new(savon_client, authentication_header)
|
123
|
+
response_hash = {
|
124
|
+
:success_sync_lead => {
|
125
|
+
:result => {
|
126
|
+
:lead_id => IDNUM,
|
127
|
+
:sync_status => {
|
128
|
+
:error => nil,
|
129
|
+
:status => 'UPDATED',
|
130
|
+
:lead_id => IDNUM
|
131
|
+
},
|
132
|
+
:lead_record => {
|
133
|
+
:email => EMAIL,
|
134
|
+
:lead_attribute_list => {
|
135
|
+
:attribute => [
|
136
|
+
{:attr_name => 'name1', :attr_type => 'string', :attr_value => 'val1'},
|
137
|
+
{:attr_name => 'name2', :attr_type => 'string', :attr_value => 'val2'},
|
138
|
+
{:attr_name => 'name3', :attr_type => 'string', :attr_value => 'val3'},
|
139
|
+
{:attr_name => 'name4', :attr_type => 'string', :attr_value => 'val4'}
|
140
|
+
]
|
141
|
+
},
|
142
|
+
:foreign_sys_type => nil,
|
143
|
+
:foreign_sys_person_id => nil,
|
144
|
+
:id => IDNUM.to_s
|
145
|
+
}
|
146
|
+
}
|
147
|
+
}
|
148
|
+
}
|
149
|
+
expect_request(savon_client,
|
150
|
+
authentication_header,
|
151
|
+
equals_matcher({
|
152
|
+
:return_lead => true,
|
153
|
+
:lead_record => {
|
154
|
+
:email => EMAIL,
|
155
|
+
:lead_attribute_list =>
|
156
|
+
{
|
157
|
+
:attribute => [
|
158
|
+
{:attr_value => "val1",
|
159
|
+
:attr_name => "name1",
|
160
|
+
:attr_type => "string"},
|
161
|
+
{:attr_value => "val2",
|
162
|
+
:attr_name => "name2",
|
163
|
+
:attr_type => "string"},
|
164
|
+
{:attr_value => EMAIL,
|
165
|
+
:attr_name => "Email",
|
166
|
+
:attr_type => "string"}
|
167
|
+
]}}}),
|
168
|
+
'ns1:paramsSyncLead',
|
169
|
+
response_hash)
|
170
|
+
lead_record = LeadRecord.new(EMAIL)
|
171
|
+
lead_record.set_attribute('name1', 'val1')
|
172
|
+
lead_record.set_attribute('name2', 'val2')
|
173
|
+
|
174
|
+
expected_lead_record = LeadRecord.new(EMAIL, IDNUM)
|
175
|
+
expected_lead_record.set_attribute('Email', EMAIL)
|
176
|
+
expected_lead_record.set_attribute('name1', 'val1')
|
177
|
+
expected_lead_record.set_attribute('name2', 'val2')
|
178
|
+
expected_lead_record.set_attribute('name3', 'val3')
|
179
|
+
expected_lead_record.set_attribute('name4', 'val4')
|
180
|
+
client.sync_lead_record(lead_record).should == expected_lead_record
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should have the correct body format on sync_lead" do
|
184
|
+
savon_client = mock('savon_client')
|
185
|
+
authentication_header = mock('authentication_header')
|
186
|
+
client = Rapleaf::Marketo::Client.new(savon_client, authentication_header)
|
187
|
+
response_hash = {
|
188
|
+
:success_sync_lead => {
|
189
|
+
:result => {
|
190
|
+
:lead_id => IDNUM,
|
191
|
+
:sync_status => {
|
192
|
+
:error => nil,
|
193
|
+
:status => 'UPDATED',
|
194
|
+
:lead_id => IDNUM
|
195
|
+
},
|
196
|
+
:lead_record => {
|
197
|
+
:email => EMAIL,
|
198
|
+
:lead_attribute_list => {
|
199
|
+
:attribute => [
|
200
|
+
{:attr_name => 'name1', :attr_type => 'string', :attr_value => 'val1'},
|
201
|
+
{:attr_name => 'name2', :attr_type => 'string', :attr_value => 'val2'},
|
202
|
+
{:attr_name => 'name3', :attr_type => 'string', :attr_value => 'val3'},
|
203
|
+
{:attr_name => 'name4', :attr_type => 'string', :attr_value => 'val4'}
|
204
|
+
]
|
205
|
+
},
|
206
|
+
:foreign_sys_type => nil,
|
207
|
+
:foreign_sys_person_id => nil,
|
208
|
+
:id => IDNUM.to_s
|
209
|
+
}
|
210
|
+
}
|
211
|
+
}
|
212
|
+
}
|
213
|
+
|
214
|
+
expect_request(savon_client,
|
215
|
+
authentication_header,
|
216
|
+
Proc.new { |actual|
|
217
|
+
actual_attribute_list = actual[:lead_record][:lead_attribute_list][:attribute]
|
218
|
+
actual[:lead_record][:lead_attribute_list][:attribute] = nil
|
219
|
+
expected = {
|
220
|
+
:return_lead => true,
|
221
|
+
:lead_record => {
|
222
|
+
:email => "some@email.com",
|
223
|
+
:lead_attribute_list =>
|
224
|
+
{
|
225
|
+
:attribute => nil}}
|
226
|
+
}
|
227
|
+
actual.should == expected
|
228
|
+
actual_attribute_list.should =~ [
|
229
|
+
{:attr_value => FIRST,
|
230
|
+
:attr_name => "FirstName",
|
231
|
+
:attr_type => "string"},
|
232
|
+
{:attr_value => LAST,
|
233
|
+
:attr_name => "LastName",
|
234
|
+
:attr_type => "string"},
|
235
|
+
{:attr_value => EMAIL,
|
236
|
+
:attr_name =>"Email",
|
237
|
+
:attr_type => "string"},
|
238
|
+
{:attr_value => COMPANY,
|
239
|
+
:attr_name => "Company",
|
240
|
+
:attr_type => "string"},
|
241
|
+
{:attr_value => MOBILE,
|
242
|
+
:attr_name => "MobilePhone",
|
243
|
+
:attr_type => "string"}
|
244
|
+
]
|
245
|
+
},
|
246
|
+
'ns1:paramsSyncLead',
|
247
|
+
response_hash)
|
248
|
+
expected_lead_record = LeadRecord.new(EMAIL, IDNUM)
|
249
|
+
expected_lead_record.set_attribute('name1', 'val1')
|
250
|
+
expected_lead_record.set_attribute('name2', 'val2')
|
251
|
+
expected_lead_record.set_attribute('name3', 'val3')
|
252
|
+
expected_lead_record.set_attribute('name4', 'val4')
|
253
|
+
client.sync_lead(EMAIL, FIRST, LAST, COMPANY, MOBILE).should == expected_lead_record
|
254
|
+
end
|
255
|
+
|
256
|
+
context "list operations" do
|
257
|
+
LIST_KEY = 'awesome leads list'
|
258
|
+
|
259
|
+
before(:each) do
|
260
|
+
@savon_client = mock('savon_client')
|
261
|
+
@authentication_header = mock('authentication_header')
|
262
|
+
@client = Rapleaf::Marketo::Client.new(@savon_client, @authentication_header)
|
263
|
+
end
|
264
|
+
|
265
|
+
it "should have the correct body format on add_to_list" do
|
266
|
+
response_hash = {} # TODO
|
267
|
+
expect_request(@savon_client,
|
268
|
+
@authentication_header,
|
269
|
+
equals_matcher({
|
270
|
+
:list_operation => ListOperationType::ADD_TO,
|
271
|
+
:list_key => LIST_KEY,
|
272
|
+
:strict => 'false',
|
273
|
+
:list_member_list => {
|
274
|
+
:lead_key => [
|
275
|
+
{
|
276
|
+
:key_type => 'EMAIL',
|
277
|
+
:key_value => EMAIL
|
278
|
+
}
|
279
|
+
]
|
280
|
+
}
|
281
|
+
}),
|
282
|
+
'ns1:paramsListOperation',
|
283
|
+
response_hash)
|
284
|
+
|
285
|
+
@client.add_to_list(LIST_KEY, EMAIL).should == response_hash
|
286
|
+
end
|
287
|
+
|
288
|
+
it "should have the correct body format on remove_from_list" do
|
289
|
+
response_hash = {} # TODO
|
290
|
+
expect_request(@savon_client,
|
291
|
+
@authentication_header,
|
292
|
+
equals_matcher({
|
293
|
+
:list_operation => ListOperationType::REMOVE_FROM,
|
294
|
+
:list_key => LIST_KEY,
|
295
|
+
:strict => 'false',
|
296
|
+
:list_member_list => {
|
297
|
+
:lead_key => [
|
298
|
+
{
|
299
|
+
:key_type => 'EMAIL',
|
300
|
+
:key_value => EMAIL
|
301
|
+
}
|
302
|
+
]
|
303
|
+
}
|
304
|
+
}),
|
305
|
+
'ns1:paramsListOperation',
|
306
|
+
response_hash)
|
307
|
+
|
308
|
+
@client.remove_from_list(LIST_KEY, EMAIL).should == response_hash
|
309
|
+
end
|
310
|
+
|
311
|
+
it "should have the correct body format on is_member_of_list?" do
|
312
|
+
response_hash = {} # TODO
|
313
|
+
expect_request(@savon_client,
|
314
|
+
@authentication_header,
|
315
|
+
equals_matcher({
|
316
|
+
:list_operation => ListOperationType::IS_MEMBER_OF,
|
317
|
+
:list_key => LIST_KEY,
|
318
|
+
:strict => 'false',
|
319
|
+
:list_member_list => {
|
320
|
+
:lead_key => [
|
321
|
+
{
|
322
|
+
:key_type => 'EMAIL',
|
323
|
+
:key_value => EMAIL
|
324
|
+
}
|
325
|
+
]
|
326
|
+
}
|
327
|
+
}),
|
328
|
+
'ns1:paramsListOperation',
|
329
|
+
response_hash)
|
330
|
+
|
331
|
+
@client.is_member_of_list?(LIST_KEY, EMAIL).should == response_hash
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
private
|
337
|
+
|
338
|
+
def equals_matcher(expected)
|
339
|
+
Proc.new { |actual|
|
340
|
+
actual.should == expected
|
341
|
+
}
|
342
|
+
end
|
343
|
+
|
344
|
+
def expect_request(savon_client, authentication_header, expected_body_matcher, expected_namespace, response_hash)
|
345
|
+
header_hash = stub('header_hash')
|
346
|
+
soap_response = stub('soap_response')
|
347
|
+
request_namespace = mock('namespace')
|
348
|
+
request_header = mock('request_header')
|
349
|
+
soap_request = mock('soap_request')
|
350
|
+
authentication_header.should_receive(:set_time)
|
351
|
+
authentication_header.should_receive(:to_hash).and_return(header_hash)
|
352
|
+
request_namespace.should_receive(:[]=).with("xmlns:ns1", "http://www.marketo.com/mktows/")
|
353
|
+
request_header.should_receive(:[]=).with("ns1:AuthenticationHeader", header_hash)
|
354
|
+
soap_request.should_receive(:namespaces).and_return(request_namespace)
|
355
|
+
soap_request.should_receive(:header).and_return(request_header)
|
356
|
+
soap_request.should_receive(:body=) do |actual_body|
|
357
|
+
expected_body_matcher.call(actual_body)
|
358
|
+
end
|
359
|
+
soap_response.should_receive(:to_hash).and_return(response_hash)
|
360
|
+
savon_client.should_receive(:request).with(expected_namespace).and_yield(soap_request).and_return(soap_response)
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
describe ListOperationType do
|
365
|
+
it 'should define the correct types' do
|
366
|
+
ListOperationType::ADD_TO.should == 'ADDTOLIST'
|
367
|
+
ListOperationType::IS_MEMBER_OF.should == 'ISMEMBEROFLIST'
|
368
|
+
ListOperationType::REMOVE_FROM.should == 'REMOVEFROMLIST'
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
module Rapleaf
|
4
|
+
module Marketo
|
5
|
+
describe LeadKeyType do
|
6
|
+
it "should define the correct types" do
|
7
|
+
LeadKeyType::IDNUM.should == 'IDNUM'
|
8
|
+
LeadKeyType::COOKIE.should == 'COOKIE'
|
9
|
+
LeadKeyType::EMAIL.should == 'EMAIL'
|
10
|
+
LeadKeyType::LEADOWNEREMAIL.should == 'LEADOWNEREMAIL'
|
11
|
+
LeadKeyType::SFDCACCOUNTID.should == 'SFDCACCOUNTID'
|
12
|
+
LeadKeyType::SFDCCONTACTID.should == 'SFDCCONTACTID'
|
13
|
+
LeadKeyType::SFDCLEADID.should == 'SFDCLEADID'
|
14
|
+
LeadKeyType::SFDCLEADOWNERID.should == 'SFDCLEADOWNERID'
|
15
|
+
LeadKeyType::SFDCOPPTYID.should == 'SFDCOPPTYID'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe LeadKey do
|
20
|
+
it "should store type and value on construction" do
|
21
|
+
KEY_VALUE = 'a value'
|
22
|
+
KEY_TYPE = LeadKeyType::IDNUM
|
23
|
+
lead_key = LeadKey.new(KEY_TYPE, KEY_VALUE)
|
24
|
+
lead_key.key_type.should == KEY_TYPE
|
25
|
+
lead_key.key_value.should == KEY_VALUE
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should to_hash correctly" do
|
29
|
+
KEY_VALUE = 'a value'
|
30
|
+
KEY_TYPE = LeadKeyType::IDNUM
|
31
|
+
lead_key = LeadKey.new(KEY_TYPE, KEY_VALUE)
|
32
|
+
|
33
|
+
lead_key.to_hash.should == {
|
34
|
+
:key_type => KEY_TYPE,
|
35
|
+
:key_value => KEY_VALUE
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
module Rapleaf
|
4
|
+
module Marketo
|
5
|
+
EMAIL = 'some@email.com'
|
6
|
+
IDNUM = 93480938
|
7
|
+
|
8
|
+
describe LeadRecord do
|
9
|
+
it "should store the idnum" do
|
10
|
+
lead_record = LeadRecord.new(EMAIL, IDNUM)
|
11
|
+
lead_record.idnum.should == IDNUM
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should store the email" do
|
15
|
+
LeadRecord.new(EMAIL, IDNUM).email.should == EMAIL
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should implement == sensibly" do
|
19
|
+
lead_record1 = LeadRecord.new(EMAIL, IDNUM)
|
20
|
+
lead_record1.set_attribute('favourite color', 'red')
|
21
|
+
lead_record1.set_attribute('age', '100')
|
22
|
+
|
23
|
+
lead_record2 = LeadRecord.new(EMAIL, IDNUM)
|
24
|
+
lead_record2.set_attribute('favourite color', 'red')
|
25
|
+
lead_record2.set_attribute('age', '100')
|
26
|
+
|
27
|
+
lead_record1.should == lead_record2
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should store when attributes are set" do
|
31
|
+
lead_record = LeadRecord.new(EMAIL, IDNUM)
|
32
|
+
lead_record.set_attribute('favourite color', 'red')
|
33
|
+
lead_record.get_attribute('favourite color').should == 'red'
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should store when attributes are updated" do
|
37
|
+
lead_record = LeadRecord.new(EMAIL, IDNUM)
|
38
|
+
lead_record.set_attribute('favourite color', 'red')
|
39
|
+
lead_record.set_attribute('favourite color', 'green')
|
40
|
+
lead_record.get_attribute('favourite color').should == 'green'
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should yield all attributes through each_attribute_pair" do
|
44
|
+
lead_record = LeadRecord.new(EMAIL, IDNUM)
|
45
|
+
lead_record.set_attribute('favourite color', 'red')
|
46
|
+
lead_record.set_attribute('favourite color', 'green')
|
47
|
+
lead_record.set_attribute('age', '99')
|
48
|
+
|
49
|
+
pairs = []
|
50
|
+
lead_record.each_attribute_pair do |attribute_name, attribute_value|
|
51
|
+
pairs << [attribute_name, attribute_value]
|
52
|
+
end
|
53
|
+
|
54
|
+
pairs.size.should == 3
|
55
|
+
pairs.should include(['favourite color', 'green'])
|
56
|
+
pairs.should include(['age', '99'])
|
57
|
+
pairs.should include(['Email', EMAIL])
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should be instantiable from a savon hash" do
|
61
|
+
savon_hash = {
|
62
|
+
:email => EMAIL,
|
63
|
+
:foreign_sys_type => nil,
|
64
|
+
:lead_attribute_list => {
|
65
|
+
:attribute => [
|
66
|
+
{ :attr_name => 'Company', :attr_type => 'string', :attr_value => 'Rapleaf'},
|
67
|
+
{ :attr_name => 'FirstName', :attr_type => 'string', :attr_value => 'James'},
|
68
|
+
{ :attr_name => 'LastName', :attr_type => 'string', :attr_value => 'O\'Brien'}
|
69
|
+
]
|
70
|
+
},
|
71
|
+
:foreign_sys_person_id => nil,
|
72
|
+
:id => IDNUM
|
73
|
+
}
|
74
|
+
|
75
|
+
actual = LeadRecord.from_hash(savon_hash)
|
76
|
+
|
77
|
+
expected = LeadRecord.new(EMAIL, IDNUM)
|
78
|
+
expected.set_attribute('Company', 'Rapleaf')
|
79
|
+
expected.set_attribute('FirstName', 'James')
|
80
|
+
expected.set_attribute('LastName', 'O\'Brien')
|
81
|
+
|
82
|
+
actual.should == expected
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: njones-marketo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 2
|
8
|
+
- 5
|
9
|
+
version: 1.2.5
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- James O'Brien (orginal author)
|
13
|
+
- Nika Jones
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-11-29 00:00:00 -06:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rspec
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 2
|
30
|
+
- 3
|
31
|
+
- 0
|
32
|
+
version: 2.3.0
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: savon
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
segments:
|
43
|
+
- 0
|
44
|
+
- 8
|
45
|
+
- 3
|
46
|
+
version: 0.8.3
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id002
|
49
|
+
description: " A Fork of the Rapleaf marketo-gem. Once the updates in the gem are merged into that one, you should use that.\n\n Allows easy integration with marketo from ruby. You can synchronize leads (multiple leads too) and fetch them back by email. This is based on the SOAP wsdl file: http://app.marketo.com/soap/mktows/1_7?WSDL (by default, but you can change on the fly). More information at https://www.rapleaf.com/developers/marketo. And look to https://github.com/njones/marketo_gem/tree/njones-marketo for updates.\n"
|
50
|
+
email: njones@appcelerator.com
|
51
|
+
executables: []
|
52
|
+
|
53
|
+
extensions: []
|
54
|
+
|
55
|
+
extra_rdoc_files: []
|
56
|
+
|
57
|
+
files:
|
58
|
+
- lib/marketo/authentication_header.rb
|
59
|
+
- lib/marketo/client.rb
|
60
|
+
- lib/marketo/enums.rb
|
61
|
+
- lib/marketo/lead_key.rb
|
62
|
+
- lib/marketo/lead_record.rb
|
63
|
+
- lib/njones-marketo.rb
|
64
|
+
has_rdoc: true
|
65
|
+
homepage: https://github.com/njones/marketo_gem
|
66
|
+
licenses: []
|
67
|
+
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options:
|
70
|
+
- --title
|
71
|
+
- Marketo Client Gem
|
72
|
+
- --main
|
73
|
+
- Rapleaf::Marketo::Client
|
74
|
+
require_paths:
|
75
|
+
- - lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
segments:
|
81
|
+
- 0
|
82
|
+
version: "0"
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
segments:
|
88
|
+
- 0
|
89
|
+
version: "0"
|
90
|
+
requirements: []
|
91
|
+
|
92
|
+
rubyforge_project:
|
93
|
+
rubygems_version: 1.3.6
|
94
|
+
signing_key:
|
95
|
+
specification_version: 3
|
96
|
+
summary: A client for using the marketo API
|
97
|
+
test_files:
|
98
|
+
- spec/marketo/authentication_header_spec.rb
|
99
|
+
- spec/marketo/client_spec.rb
|
100
|
+
- spec/marketo/lead_key_spec.rb
|
101
|
+
- spec/marketo/lead_record_spec.rb
|