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