etapi 0.1.1
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/.gitignore +5 -0
- data/Gemfile +3 -0
- data/README.md +34 -0
- data/Rakefile +1 -0
- data/etapi.gemspec +22 -0
- data/lib/etapi/call_builder.rb +70 -0
- data/lib/etapi/calls/email.rb +33 -0
- data/lib/etapi/calls/list.rb +28 -0
- data/lib/etapi/calls/subscriber.rb +178 -0
- data/lib/etapi/calls/tracking.rb +32 -0
- data/lib/etapi/configuration.rb +49 -0
- data/lib/etapi/error.rb +46 -0
- data/lib/etapi/exact_target.rb +52 -0
- data/lib/etapi/version.rb +3 -0
- data/lib/etapi.rb +10 -0
- metadata +111 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
ExactTarget API Wrapper
|
2
|
+
=======================
|
3
|
+
|
4
|
+
ETAPI is an ExactTarget API wrapper for XML calls.
|
5
|
+
|
6
|
+
Documentation
|
7
|
+
------------
|
8
|
+
[Wiki](https://github.com/Phiction/etapi/wiki)
|
9
|
+
|
10
|
+
TODO
|
11
|
+
====
|
12
|
+
|
13
|
+
Subscriber Management
|
14
|
+
---
|
15
|
+
`subscriber_add` : add s4 `:account_id`, add `:status`
|
16
|
+
`subscriber_edit` : add s4 `:account_id`, add `:status`
|
17
|
+
`subscriber_retrieve` : add s4 `:account_id`, add `:status`
|
18
|
+
`subscriber_retrieve_from_list`
|
19
|
+
`subscriber_retrieve_from_list` : add s4 `:account_id`, add `:status`
|
20
|
+
`subscriber_retrieve_lists`
|
21
|
+
`subscriber_retrieve_lists` : add s4 `:account_id`, add `:status`
|
22
|
+
`subscriber_unsubscribe_master` : multiple email addresses
|
23
|
+
|
24
|
+
List Management
|
25
|
+
---
|
26
|
+
`list_retrieve_subscribers` : add s4 `:account_id`, add `:status`
|
27
|
+
|
28
|
+
Email Management
|
29
|
+
---
|
30
|
+
`email_retrieve_body` : have access to sub accounts?
|
31
|
+
|
32
|
+
XML
|
33
|
+
===
|
34
|
+
Any other XML calls available will be added by request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/etapi.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
|
+
$:.unshift lib unless $:.include? lib
|
3
|
+
|
4
|
+
require "etapi/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "etapi"
|
8
|
+
s.version = ETAPI::Version
|
9
|
+
s.authors = ["Chris McGrath"]
|
10
|
+
s.email = ["mcgrath.chris@gmail.com"]
|
11
|
+
s.homepage = %q{http://github.com/phiction/etapi}
|
12
|
+
s.summary = %q{Ruby Wrapper for Exact Target's APIs}
|
13
|
+
s.description = %q{This is an attempt to make integrating easier with Exact Target's XML APIs.}
|
14
|
+
|
15
|
+
s.rubyforge_project = "etapi"
|
16
|
+
|
17
|
+
s.add_dependency("builder", ">= 2.1.2")
|
18
|
+
s.add_dependency("nokogiri", ">= 1.4.1")
|
19
|
+
|
20
|
+
s.files = `git ls-files`.split("\n")
|
21
|
+
s.require_path = "lib"
|
22
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module ETAPI
|
2
|
+
|
3
|
+
class Session
|
4
|
+
|
5
|
+
def build_call(type, method, *args)
|
6
|
+
|
7
|
+
options = args.extract_options!
|
8
|
+
ignore_parse = options[:ignore_parse] || false
|
9
|
+
|
10
|
+
data = ""
|
11
|
+
xml = Builder::XmlMarkup.new(:target => data, :indent => 2)
|
12
|
+
xml.instruct!
|
13
|
+
xml.exacttarget do
|
14
|
+
xml.authorization do
|
15
|
+
xml.username @username
|
16
|
+
xml.password @password
|
17
|
+
end
|
18
|
+
xml.system do
|
19
|
+
xml.system_name type
|
20
|
+
xml.action method
|
21
|
+
for parameter in @parameters
|
22
|
+
if parameter[0] == "values"
|
23
|
+
xml.values do
|
24
|
+
parameter[1].each do |key, value|
|
25
|
+
eval("xml.#{key.gsub(/\s/, '__')} '#{value}'")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
else
|
29
|
+
if parameter[1].is_a?(Hash)
|
30
|
+
xml.tag!(parameter[0]) do
|
31
|
+
parameter[1].each do |key, value|
|
32
|
+
eval("xml.#{key.gsub(/\s/, '__')} '#{value}'")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
else
|
36
|
+
eval("xml.#{parameter[0]} '#{parameter[1]}'")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
data_encoded = "qf=xml&xml=" + url_encode(data)
|
44
|
+
response = @api_url.post(@api_uri.path, data_encoded, @headers.merge('Content-length' => data_encoded.length.to_s))
|
45
|
+
check_response(response)
|
46
|
+
ignore_parse ? response.read_body : Nokogiri::XML::Document.parse(response.read_body)
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def print_xml(obj)
|
53
|
+
require "rexml/document"
|
54
|
+
doc = REXML::Document.new(obj.http.raw_body)
|
55
|
+
out = ""
|
56
|
+
doc.write(out, 1)
|
57
|
+
out
|
58
|
+
end
|
59
|
+
|
60
|
+
def print_full_xml(obj)
|
61
|
+
require "rexml/document"
|
62
|
+
doc = REXML::Document.new(obj)
|
63
|
+
out = ""
|
64
|
+
doc.write(out, 1)
|
65
|
+
out
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module ETAPI
|
2
|
+
|
3
|
+
class Session
|
4
|
+
|
5
|
+
def email_retrieve_body(*args)
|
6
|
+
|
7
|
+
# options
|
8
|
+
options = args.extract_options!
|
9
|
+
@email_id = options[:email_id]
|
10
|
+
|
11
|
+
# check for required options
|
12
|
+
required_options = ["email_id"]
|
13
|
+
return false unless check_required(required_options)
|
14
|
+
|
15
|
+
# merge parameters and values
|
16
|
+
type = "email"
|
17
|
+
method = "retrieve"
|
18
|
+
@parameters = {
|
19
|
+
"search_type" => "emailid",
|
20
|
+
"sub_action" => "htmlemail",
|
21
|
+
"search_value" => @email_id,
|
22
|
+
"search_value2" => "",
|
23
|
+
"search_value3" => "",
|
24
|
+
}
|
25
|
+
|
26
|
+
response = build_call(type, method)
|
27
|
+
response.xpath("//htmlbody").text rescue false
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module ETAPI
|
2
|
+
|
3
|
+
class Session
|
4
|
+
|
5
|
+
def list_retrieve_subscribers(*args)
|
6
|
+
|
7
|
+
# options
|
8
|
+
options = args.extract_options!
|
9
|
+
@list_id = options[:list_id]
|
10
|
+
|
11
|
+
# check for required options
|
12
|
+
required_options = ["list_id"]
|
13
|
+
return false unless check_required(required_options)
|
14
|
+
|
15
|
+
# merge parameters and values
|
16
|
+
@parameters = {
|
17
|
+
"search_type" => "listid",
|
18
|
+
"search_value" => @list_id
|
19
|
+
}
|
20
|
+
|
21
|
+
response = build_call("list", "retrieve_sub", {:parse_response => false})
|
22
|
+
Hash.from_xml(response)['exacttarget']['system']['list']['subscribers'].first[1] rescue false
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
module ETAPI
|
2
|
+
|
3
|
+
class Session
|
4
|
+
|
5
|
+
def subscriber_add(*args)
|
6
|
+
|
7
|
+
# options
|
8
|
+
options = args.extract_options!
|
9
|
+
@list_id = options[:list_id] ||= nil
|
10
|
+
@email = options[:email]
|
11
|
+
@values = options[:values] ||= {}
|
12
|
+
@account_id = options[:account_id]
|
13
|
+
|
14
|
+
# check for required options
|
15
|
+
required_options = ["email", "list_id"]
|
16
|
+
return false unless check_required(required_options)
|
17
|
+
|
18
|
+
# update options
|
19
|
+
@values.merge!({"Email Address" => @email, "status" => "active"})
|
20
|
+
|
21
|
+
# merge parameters and values
|
22
|
+
@parameters = {
|
23
|
+
"search_type" => "listid",
|
24
|
+
"search_value" => @list_id,
|
25
|
+
"search_value2" => "",
|
26
|
+
"values" => @values
|
27
|
+
}
|
28
|
+
|
29
|
+
response = build_call("subscriber", "add")
|
30
|
+
response.xpath("//subscriber_description").text.to_i rescue false
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
def subscriber_edit(*args)
|
35
|
+
|
36
|
+
# options
|
37
|
+
options = args.extract_options!
|
38
|
+
@subscriber_id = options[:subscriber_id]
|
39
|
+
@values = options[:values] ||= {}
|
40
|
+
@account_id = options[:account_id] ||= ""
|
41
|
+
|
42
|
+
# check for required options
|
43
|
+
required_options = ["subscriber_id"]
|
44
|
+
return false unless check_required(required_options)
|
45
|
+
|
46
|
+
# merge parameters and values
|
47
|
+
@parameters = {
|
48
|
+
"search_type" => "subid",
|
49
|
+
"search_value" => @subscriber_id,
|
50
|
+
"search_value2" => "",
|
51
|
+
"values" => @values
|
52
|
+
}
|
53
|
+
|
54
|
+
response = build_call("subscriber", "edit")
|
55
|
+
response.xpath("//subscriber_description").text == @subscriber_id.to_s rescue false
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
def subscriber_edit_from_list(*args)
|
60
|
+
|
61
|
+
# options
|
62
|
+
options = args.extract_options!
|
63
|
+
@list_id = options[:list_id]
|
64
|
+
@email = options[:email]
|
65
|
+
@values = options[:values] ||= {}
|
66
|
+
@account_id = options[:account_id] ||= ""
|
67
|
+
|
68
|
+
# check for required options
|
69
|
+
required_options = ["list_id", "email"]
|
70
|
+
return false unless check_required(required_options)
|
71
|
+
|
72
|
+
# merge parameters and values
|
73
|
+
@parameters = {
|
74
|
+
"search_type" => "listid",
|
75
|
+
"search_value" => @list_id,
|
76
|
+
"search_value2" => @email,
|
77
|
+
"values" => @values
|
78
|
+
}
|
79
|
+
|
80
|
+
response = build_call("subscriber", "edit")
|
81
|
+
response.xpath("//subscriber_description").text.blank? && response.xpath("//subscriber_info").text.blank? ? false : true rescue false
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
def subscriber_delete(*args)
|
86
|
+
|
87
|
+
# options
|
88
|
+
options = args.extract_options!
|
89
|
+
@subscriber_id = options[:subscriber_id]
|
90
|
+
|
91
|
+
# check for required options
|
92
|
+
required_options = ["subscriber_id"]
|
93
|
+
return false unless check_required(required_options)
|
94
|
+
|
95
|
+
# merge parameters and values
|
96
|
+
@parameters = {
|
97
|
+
"search_type" => "subid",
|
98
|
+
"search_value" => @subscriber_id,
|
99
|
+
"search_value2" => ""
|
100
|
+
}
|
101
|
+
|
102
|
+
response = build_call("subscriber", "delete")
|
103
|
+
response.xpath("//subscriber_info").text.blank? ? false : true rescue false
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
def subscriber_remove_from_list(*args)
|
108
|
+
|
109
|
+
# options
|
110
|
+
options = args.extract_options!
|
111
|
+
@list_id = options[:list_id]
|
112
|
+
@email = options[:email]
|
113
|
+
|
114
|
+
# check for required options
|
115
|
+
required_options = ["list_id", "email"]
|
116
|
+
return false unless check_required(required_options)
|
117
|
+
|
118
|
+
# merge parameters and values
|
119
|
+
@parameters = {
|
120
|
+
"search_type" => "listid",
|
121
|
+
"search_value" => @list_id,
|
122
|
+
"search_value2" => @email
|
123
|
+
}
|
124
|
+
|
125
|
+
response = build_call("subscriber", "delete")
|
126
|
+
response.xpath("//subscriber_info").text.blank? ? false : true rescue false
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
def subscriber_unsubscribe_master(*args)
|
131
|
+
|
132
|
+
# options
|
133
|
+
options = args.extract_options!
|
134
|
+
@email = options[:email]
|
135
|
+
|
136
|
+
# check for required options
|
137
|
+
required_options = ["email"]
|
138
|
+
return false unless check_required(required_options)
|
139
|
+
|
140
|
+
# merge parameters and values
|
141
|
+
@parameters = {
|
142
|
+
"search_type" => "emailaddress",
|
143
|
+
"search_value" => {
|
144
|
+
"emailaddress" => @email
|
145
|
+
}
|
146
|
+
}
|
147
|
+
|
148
|
+
response = build_call("subscriber", "masterunsub")
|
149
|
+
response.xpath("//emailaddress").text == @email ? true : false rescue false
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
def subscriber_retrieve(*args)
|
154
|
+
|
155
|
+
# options
|
156
|
+
options = args.extract_options!
|
157
|
+
@subscriber_id = options[:subscriber_id]
|
158
|
+
@account_id = options[:account_id] ||= ""
|
159
|
+
|
160
|
+
# check for required options
|
161
|
+
required_options = ["subscriber_id"]
|
162
|
+
return false unless check_required(required_options)
|
163
|
+
|
164
|
+
# merge parameters and values
|
165
|
+
@parameters = {
|
166
|
+
"search_type" => "subid",
|
167
|
+
"search_value" => @subscriber_id,
|
168
|
+
"search_value2" => ""
|
169
|
+
}
|
170
|
+
|
171
|
+
response = build_call("subscriber", "retrieve", {:ignore_parse => true})
|
172
|
+
Hash.from_xml(response)['exacttarget']['system']['subscriber'].first rescue false
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module ETAPI
|
2
|
+
|
3
|
+
class Session
|
4
|
+
|
5
|
+
def tracking_retrieve(*args)
|
6
|
+
|
7
|
+
# options
|
8
|
+
options = args.extract_options!
|
9
|
+
@job_id = options[:job_id]
|
10
|
+
|
11
|
+
# check for required options
|
12
|
+
required_options = ["job_id"]
|
13
|
+
return false unless check_required(required_options)
|
14
|
+
|
15
|
+
# merge parameters and values
|
16
|
+
type = "tracking"
|
17
|
+
method = "retrieve"
|
18
|
+
@parameters = {
|
19
|
+
"search_type" => "jobID",
|
20
|
+
"sub_action" => "summary",
|
21
|
+
"search_value" => @job_id,
|
22
|
+
"search_value2" => ""
|
23
|
+
}
|
24
|
+
|
25
|
+
response = build_call(type, method, {:parse_response => false})
|
26
|
+
Hash.from_xml(response)['exacttarget']['system']['tracking']['emailSummary'] rescue false
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require("erb")
|
2
|
+
require("uri")
|
3
|
+
require("logger")
|
4
|
+
require("builder")
|
5
|
+
require("nokogiri")
|
6
|
+
require("net/https")
|
7
|
+
require("etapi/error")
|
8
|
+
require("etapi/exact_target")
|
9
|
+
require("etapi/call_builder")
|
10
|
+
|
11
|
+
include(ERB::Util)
|
12
|
+
|
13
|
+
module ETAPI
|
14
|
+
module Configuration
|
15
|
+
|
16
|
+
attr_accessor(
|
17
|
+
:username,
|
18
|
+
:password,
|
19
|
+
:use_s4,
|
20
|
+
:raise_errors,
|
21
|
+
:log
|
22
|
+
)
|
23
|
+
|
24
|
+
attr_writer(:log)
|
25
|
+
def log?
|
26
|
+
@log != false
|
27
|
+
end
|
28
|
+
|
29
|
+
def log(message)
|
30
|
+
logger.send(log_level, "\n#{message}\n") if log?
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_writer(:logger)
|
34
|
+
def logger
|
35
|
+
@logger ||= ::Logger.new(STDOUT)
|
36
|
+
end
|
37
|
+
|
38
|
+
attr_writer(:log_level)
|
39
|
+
def log_level
|
40
|
+
@log_level ||= :debug
|
41
|
+
end
|
42
|
+
|
43
|
+
attr_writer(:raise_errors)
|
44
|
+
def raise_errors?
|
45
|
+
@raise_errors != false
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
data/lib/etapi/error.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
module ETAPI
|
2
|
+
|
3
|
+
class Session
|
4
|
+
|
5
|
+
def check_response(response)
|
6
|
+
|
7
|
+
raise Error.new(-1, 'Network error') if response.class != Net::HTTPOK
|
8
|
+
|
9
|
+
response = Nokogiri::XML::Document.parse(response.body)
|
10
|
+
|
11
|
+
error_code = response.xpath("//error")
|
12
|
+
error_msg = response.xpath("//error_description")
|
13
|
+
|
14
|
+
if !error_code.blank? && !error_msg.blank?
|
15
|
+
if ETAPI.raise_errors?
|
16
|
+
raise(RuntimeError, "\n\n Code: #{error_code.text.to_i}\n Message: #{error_msg.text}\n\n")
|
17
|
+
else
|
18
|
+
ETAPI.log(" Code: #{error_code.text.to_i}\n Message: #{error_msg.text}") if ETAPI.log?
|
19
|
+
return false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
def check_required(required_options)
|
26
|
+
missing_options = []
|
27
|
+
|
28
|
+
for option in required_options
|
29
|
+
missing_options << ":#{option}" if eval("@#{option}.blank?")
|
30
|
+
end
|
31
|
+
|
32
|
+
if !missing_options.blank?
|
33
|
+
if ETAPI.log?
|
34
|
+
ETAPI.log(" Code: ETAPI\n Message: missing #{missing_options.join(', ')}")
|
35
|
+
elsif ETAPI.raise_errors?
|
36
|
+
raise(ArgumentError, "\n\n Code: ETAPI\n Message: missing #{missing_options.join(', ')}\n\n")
|
37
|
+
end
|
38
|
+
return false
|
39
|
+
end
|
40
|
+
|
41
|
+
return true
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require("etapi/calls/list")
|
2
|
+
require("etapi/calls/email")
|
3
|
+
require("etapi/calls/tracking")
|
4
|
+
require("etapi/calls/subscriber")
|
5
|
+
|
6
|
+
module ETAPI
|
7
|
+
|
8
|
+
class Session
|
9
|
+
|
10
|
+
# set default options
|
11
|
+
DEFAULTS = {
|
12
|
+
:api_method => :xml,
|
13
|
+
:use_s4 => false,
|
14
|
+
:api_uri_xml => "https://api.dc1.exacttarget.com/integrate.aspx",
|
15
|
+
:api_uri_xml_s4 => "https://api.s4.exacttarget.com/integrate.aspx",
|
16
|
+
:use_ssl => true,
|
17
|
+
}
|
18
|
+
|
19
|
+
# allowed options
|
20
|
+
ALLOWED_USE_S4_OPTIONS = [true, false]
|
21
|
+
|
22
|
+
# initialize a new exact target instance
|
23
|
+
def initialize(*args)
|
24
|
+
|
25
|
+
# merge options with configuration
|
26
|
+
options = args.extract_options!
|
27
|
+
@username = options[:username] ||= ETAPI.username
|
28
|
+
@password = options[:password] ||= ETAPI.password
|
29
|
+
@use_s4 = options[:use_s4] ||= ETAPI.use_s4 ||= DEFAULTS[:use_s4]
|
30
|
+
@headers = {"Content-Type" => "application/x-www-form-urlencoded", "Connection" => "close"}
|
31
|
+
|
32
|
+
# check for required options
|
33
|
+
raise ArgumentError, "* missing :username *" if @username.blank?
|
34
|
+
raise ArgumentError, "* missing :password *" if @password.blank?
|
35
|
+
raise ArgumentError, "* invalid :use_s4 | options => [true, false] *" unless ALLOWED_USE_S4_OPTIONS.include?(@use_s4)
|
36
|
+
|
37
|
+
@api_uri = @use_s4 ? DEFAULTS[:api_uri_xml_s4] : DEFAULTS[:api_uri_xml]
|
38
|
+
|
39
|
+
@api_wsdl = @api_uri if @use_s4
|
40
|
+
|
41
|
+
# parse uri
|
42
|
+
@api_uri = URI.parse(@api_uri)
|
43
|
+
@api_url = Net::HTTP.new(@api_uri.host, @api_uri.port)
|
44
|
+
|
45
|
+
# check for SSL (disabled)
|
46
|
+
@api_url.use_ssl = options[:use_ssl] ||= DEFAULTS[:use_ssl]
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
data/lib/etapi.rb
ADDED
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: etapi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 25
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 1
|
10
|
+
version: 0.1.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Chris McGrath
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-09-03 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: builder
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 15
|
29
|
+
segments:
|
30
|
+
- 2
|
31
|
+
- 1
|
32
|
+
- 2
|
33
|
+
version: 2.1.2
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: nokogiri
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 5
|
45
|
+
segments:
|
46
|
+
- 1
|
47
|
+
- 4
|
48
|
+
- 1
|
49
|
+
version: 1.4.1
|
50
|
+
type: :runtime
|
51
|
+
version_requirements: *id002
|
52
|
+
description: This is an attempt to make integrating easier with Exact Target's XML APIs.
|
53
|
+
email:
|
54
|
+
- mcgrath.chris@gmail.com
|
55
|
+
executables: []
|
56
|
+
|
57
|
+
extensions: []
|
58
|
+
|
59
|
+
extra_rdoc_files: []
|
60
|
+
|
61
|
+
files:
|
62
|
+
- .gitignore
|
63
|
+
- Gemfile
|
64
|
+
- README.md
|
65
|
+
- Rakefile
|
66
|
+
- etapi.gemspec
|
67
|
+
- lib/etapi.rb
|
68
|
+
- lib/etapi/call_builder.rb
|
69
|
+
- lib/etapi/calls/email.rb
|
70
|
+
- lib/etapi/calls/list.rb
|
71
|
+
- lib/etapi/calls/subscriber.rb
|
72
|
+
- lib/etapi/calls/tracking.rb
|
73
|
+
- lib/etapi/configuration.rb
|
74
|
+
- lib/etapi/error.rb
|
75
|
+
- lib/etapi/exact_target.rb
|
76
|
+
- lib/etapi/version.rb
|
77
|
+
homepage: http://github.com/phiction/etapi
|
78
|
+
licenses: []
|
79
|
+
|
80
|
+
post_install_message:
|
81
|
+
rdoc_options: []
|
82
|
+
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
hash: 3
|
91
|
+
segments:
|
92
|
+
- 0
|
93
|
+
version: "0"
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
hash: 3
|
100
|
+
segments:
|
101
|
+
- 0
|
102
|
+
version: "0"
|
103
|
+
requirements: []
|
104
|
+
|
105
|
+
rubyforge_project: etapi
|
106
|
+
rubygems_version: 1.8.10
|
107
|
+
signing_key:
|
108
|
+
specification_version: 3
|
109
|
+
summary: Ruby Wrapper for Exact Target's APIs
|
110
|
+
test_files: []
|
111
|
+
|