campaign_monitor 0.1.0

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.
Files changed (137) hide show
  1. data/CHANGELOG +3 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README +30 -0
  4. data/TODO +3 -0
  5. data/doc/classes/CMCampaignSummary.html +170 -0
  6. data/doc/classes/CMCampaignSummary.src/M000003.html +22 -0
  7. data/doc/classes/CMClient.html +111 -0
  8. data/doc/classes/CMResult.html +155 -0
  9. data/doc/classes/CMResult.src/M000004.html +19 -0
  10. data/doc/classes/CampaignMonitor.html +355 -0
  11. data/doc/classes/CampaignMonitor.src/M000001.html +20 -0
  12. data/doc/classes/CampaignMonitor.src/M000002.html +20 -0
  13. data/doc/classes/CampaignMonitor.src/M000003.html +19 -0
  14. data/doc/classes/CampaignMonitor.src/M000004.html +20 -0
  15. data/doc/classes/CampaignMonitor.src/M000005.html +18 -0
  16. data/doc/classes/CampaignMonitor.src/M000006.html +18 -0
  17. data/doc/classes/CampaignMonitor.src/M000007.html +23 -0
  18. data/doc/classes/CampaignMonitor.src/M000008.html +23 -0
  19. data/doc/classes/CampaignMonitor.src/M000009.html +23 -0
  20. data/doc/classes/CampaignMonitor.src/M000010.html +19 -0
  21. data/doc/classes/CampaignMonitor.src/M000011.html +19 -0
  22. data/doc/classes/CampaignMonitor.src/M000012.html +18 -0
  23. data/doc/classes/CampaignMonitor.src/M000013.html +18 -0
  24. data/doc/classes/CampaignMonitor.src/M000014.html +18 -0
  25. data/doc/classes/CampaignMonitor.src/M000015.html +19 -0
  26. data/doc/classes/CampaignMonitor.src/M000016.html +18 -0
  27. data/doc/classes/CampaignMonitor.src/M000017.html +18 -0
  28. data/doc/classes/CampaignMonitor.src/M000018.html +18 -0
  29. data/doc/classes/CampaignMonitor.src/M000019.html +18 -0
  30. data/doc/classes/CampaignMonitor.src/M000020.html +18 -0
  31. data/doc/classes/CampaignMonitor.src/M000021.html +18 -0
  32. data/doc/classes/CampaignMonitor.src/M000022.html +18 -0
  33. data/doc/classes/CampaignMonitor.src/M000023.html +18 -0
  34. data/doc/classes/CampaignMonitor.src/M000024.html +29 -0
  35. data/doc/classes/CampaignMonitor.src/M000025.html +19 -0
  36. data/doc/classes/CampaignMonitor.src/M000026.html +21 -0
  37. data/doc/classes/CampaignMonitor.src/M000027.html +20 -0
  38. data/doc/classes/CampaignMonitor.src/M000028.html +19 -0
  39. data/doc/classes/CampaignMonitor.src/M000029.html +20 -0
  40. data/doc/classes/CampaignMonitor.src/M000030.html +18 -0
  41. data/doc/classes/CampaignMonitor.src/M000031.html +18 -0
  42. data/doc/classes/CampaignMonitor.src/M000032.html +23 -0
  43. data/doc/classes/CampaignMonitor.src/M000033.html +23 -0
  44. data/doc/classes/CampaignMonitor.src/M000034.html +23 -0
  45. data/doc/classes/CampaignMonitor.src/M000035.html +19 -0
  46. data/doc/classes/CampaignMonitor/Campaign.html +387 -0
  47. data/doc/classes/CampaignMonitor/Campaign.src/M000027.html +22 -0
  48. data/doc/classes/CampaignMonitor/Campaign.src/M000028.html +22 -0
  49. data/doc/classes/CampaignMonitor/Campaign.src/M000029.html +23 -0
  50. data/doc/classes/CampaignMonitor/Campaign.src/M000030.html +23 -0
  51. data/doc/classes/CampaignMonitor/Campaign.src/M000031.html +23 -0
  52. data/doc/classes/CampaignMonitor/Campaign.src/M000032.html +23 -0
  53. data/doc/classes/CampaignMonitor/Campaign.src/M000033.html +18 -0
  54. data/doc/classes/CampaignMonitor/Campaign.src/M000034.html +18 -0
  55. data/doc/classes/CampaignMonitor/Campaign.src/M000035.html +18 -0
  56. data/doc/classes/CampaignMonitor/Campaign.src/M000036.html +18 -0
  57. data/doc/classes/CampaignMonitor/Campaign.src/M000037.html +18 -0
  58. data/doc/classes/CampaignMonitor/Campaign.src/M000053.html +22 -0
  59. data/doc/classes/CampaignMonitor/Campaign.src/M000054.html +23 -0
  60. data/doc/classes/CampaignMonitor/Campaign.src/M000055.html +23 -0
  61. data/doc/classes/CampaignMonitor/Campaign.src/M000056.html +23 -0
  62. data/doc/classes/CampaignMonitor/Campaign.src/M000057.html +23 -0
  63. data/doc/classes/CampaignMonitor/Campaign.src/M000058.html +18 -0
  64. data/doc/classes/CampaignMonitor/Campaign.src/M000059.html +18 -0
  65. data/doc/classes/CampaignMonitor/Campaign.src/M000060.html +18 -0
  66. data/doc/classes/CampaignMonitor/Campaign.src/M000061.html +18 -0
  67. data/doc/classes/CampaignMonitor/Campaign.src/M000062.html +18 -0
  68. data/doc/classes/CampaignMonitor/Client.html +226 -0
  69. data/doc/classes/CampaignMonitor/Client.src/M000016.html +20 -0
  70. data/doc/classes/CampaignMonitor/Client.src/M000017.html +20 -0
  71. data/doc/classes/CampaignMonitor/Client.src/M000018.html +23 -0
  72. data/doc/classes/CampaignMonitor/Client.src/M000019.html +23 -0
  73. data/doc/classes/CampaignMonitor/Client.src/M000042.html +20 -0
  74. data/doc/classes/CampaignMonitor/Client.src/M000043.html +23 -0
  75. data/doc/classes/CampaignMonitor/Client.src/M000044.html +23 -0
  76. data/doc/classes/CampaignMonitor/List.html +308 -0
  77. data/doc/classes/CampaignMonitor/List.src/M000021.html +20 -0
  78. data/doc/classes/CampaignMonitor/List.src/M000022.html +20 -0
  79. data/doc/classes/CampaignMonitor/List.src/M000023.html +19 -0
  80. data/doc/classes/CampaignMonitor/List.src/M000024.html +19 -0
  81. data/doc/classes/CampaignMonitor/List.src/M000025.html +23 -0
  82. data/doc/classes/CampaignMonitor/List.src/M000026.html +23 -0
  83. data/doc/classes/CampaignMonitor/List.src/M000027.html +23 -0
  84. data/doc/classes/CampaignMonitor/List.src/M000047.html +20 -0
  85. data/doc/classes/CampaignMonitor/List.src/M000048.html +19 -0
  86. data/doc/classes/CampaignMonitor/List.src/M000049.html +19 -0
  87. data/doc/classes/CampaignMonitor/List.src/M000050.html +23 -0
  88. data/doc/classes/CampaignMonitor/List.src/M000051.html +23 -0
  89. data/doc/classes/CampaignMonitor/List.src/M000052.html +23 -0
  90. data/doc/classes/CampaignMonitor/Result.html +162 -0
  91. data/doc/classes/CampaignMonitor/Result.src/M000020.html +19 -0
  92. data/doc/classes/CampaignMonitor/Result.src/M000021.html +19 -0
  93. data/doc/classes/CampaignMonitor/Result.src/M000046.html +19 -0
  94. data/doc/classes/CampaignMonitor/Subscriber.html +212 -0
  95. data/doc/classes/CampaignMonitor/Subscriber.src/M000012.html +21 -0
  96. data/doc/classes/CampaignMonitor/Subscriber.src/M000013.html +21 -0
  97. data/doc/classes/CampaignMonitor/Subscriber.src/M000014.html +19 -0
  98. data/doc/classes/CampaignMonitor/Subscriber.src/M000015.html +19 -0
  99. data/doc/classes/CampaignMonitor/Subscriber.src/M000038.html +21 -0
  100. data/doc/classes/CampaignMonitor/Subscriber.src/M000039.html +19 -0
  101. data/doc/classes/CampaignMonitor/Subscriber.src/M000040.html +19 -0
  102. data/doc/classes/CampaignMonitor/SubscriberBounce.html +166 -0
  103. data/doc/classes/CampaignMonitor/SubscriberBounce.src/M000019.html +20 -0
  104. data/doc/classes/CampaignMonitor/SubscriberBounce.src/M000020.html +20 -0
  105. data/doc/classes/CampaignMonitor/SubscriberBounce.src/M000045.html +20 -0
  106. data/doc/classes/CampaignMonitor/SubscriberClick.html +166 -0
  107. data/doc/classes/CampaignMonitor/SubscriberClick.src/M000010.html +20 -0
  108. data/doc/classes/CampaignMonitor/SubscriberClick.src/M000011.html +20 -0
  109. data/doc/classes/CampaignMonitor/SubscriberClick.src/M000036.html +20 -0
  110. data/doc/classes/CampaignMonitor/SubscriberOpen.html +166 -0
  111. data/doc/classes/CampaignMonitor/SubscriberOpen.src/M000011.html +20 -0
  112. data/doc/classes/CampaignMonitor/SubscriberOpen.src/M000012.html +20 -0
  113. data/doc/classes/CampaignMonitor/SubscriberOpen.src/M000037.html +20 -0
  114. data/doc/classes/CampaignMonitor/SubscriberUnsubscribe.html +161 -0
  115. data/doc/classes/CampaignMonitor/SubscriberUnsubscribe.src/M000015.html +19 -0
  116. data/doc/classes/CampaignMonitor/SubscriberUnsubscribe.src/M000016.html +19 -0
  117. data/doc/classes/CampaignMonitor/SubscriberUnsubscribe.src/M000041.html +19 -0
  118. data/doc/classes/CampaignMonitorTest.html +137 -0
  119. data/doc/classes/CampaignMonitorTest.src/M000001.html +18 -0
  120. data/doc/classes/Hash.html +137 -0
  121. data/doc/classes/Hash.src/M000002.html +18 -0
  122. data/doc/classes/Symbol.html +143 -0
  123. data/doc/classes/Symbol.src/M000001.html +18 -0
  124. data/doc/created.rid +1 -0
  125. data/doc/files/campaign_monitor_old_rb.html +119 -0
  126. data/doc/files/init_rb.html +108 -0
  127. data/doc/files/install_rb.html +101 -0
  128. data/doc/files/lib/campaign_monitor_rb.html +184 -0
  129. data/doc/files/test/campaign_monitor_test_rb.html +101 -0
  130. data/doc/fr_class_index.html +37 -0
  131. data/doc/fr_file_index.html +28 -0
  132. data/doc/fr_method_index.html +63 -0
  133. data/doc/index.html +24 -0
  134. data/doc/rdoc-style.css +208 -0
  135. data/lib/campaign_monitor.rb +503 -0
  136. data/test/campaign_monitor_test.rb +6 -0
  137. metadata +175 -0
@@ -0,0 +1,63 @@
1
+
2
+ <?xml version="1.0" encoding="iso-8859-1"?>
3
+ <!DOCTYPE html
4
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
5
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
6
+
7
+ <!--
8
+
9
+ Methods
10
+
11
+ -->
12
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
13
+ <head>
14
+ <title>Methods</title>
15
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
16
+ <link rel="stylesheet" href="rdoc-style.css" type="text/css" />
17
+ <base target="docwin" />
18
+ </head>
19
+ <body>
20
+ <div id="index">
21
+ <h1 class="section-bar">Methods</h1>
22
+ <div id="index-entries">
23
+ <a href="classes/CampaignMonitor/List.html#M000025">active_subscribers (CampaignMonitor::List)</a><br />
24
+ <a href="classes/CampaignMonitor/Subscriber.html#M000014">add (CampaignMonitor::Subscriber)</a><br />
25
+ <a href="classes/CampaignMonitor/List.html#M000023">add_subscriber (CampaignMonitor::List)</a><br />
26
+ <a href="classes/CampaignMonitor.html#M000010">add_subscriber (CampaignMonitor)</a><br />
27
+ <a href="classes/CampaignMonitor/List.html#M000027">bounced (CampaignMonitor::List)</a><br />
28
+ <a href="classes/CampaignMonitor/Campaign.html#M000030">bounces (CampaignMonitor::Campaign)</a><br />
29
+ <a href="classes/CampaignMonitor.html#M000008">campaigns (CampaignMonitor)</a><br />
30
+ <a href="classes/CampaignMonitor/Client.html#M000019">campaigns (CampaignMonitor::Client)</a><br />
31
+ <a href="classes/CampaignMonitor/Campaign.html#M000031">clicks (CampaignMonitor::Campaign)</a><br />
32
+ <a href="classes/CampaignMonitor.html#M000007">clients (CampaignMonitor)</a><br />
33
+ <a href="classes/CampaignMonitor.html#M000005">http_get (CampaignMonitor)</a><br />
34
+ <a href="classes/CampaignMonitor/Client.html#M000018">lists (CampaignMonitor::Client)</a><br />
35
+ <a href="classes/CampaignMonitor.html#M000009">lists (CampaignMonitor)</a><br />
36
+ <a href="classes/CampaignMonitor.html#M000006">method_missing (CampaignMonitor)</a><br />
37
+ <a href="classes/CampaignMonitor/Client.html#M000017">new (CampaignMonitor::Client)</a><br />
38
+ <a href="classes/CampaignMonitor/SubscriberUnsubscribe.html#M000016">new (CampaignMonitor::SubscriberUnsubscribe)</a><br />
39
+ <a href="classes/CampaignMonitor/Campaign.html#M000028">new (CampaignMonitor::Campaign)</a><br />
40
+ <a href="classes/CampaignMonitor/SubscriberOpen.html#M000012">new (CampaignMonitor::SubscriberOpen)</a><br />
41
+ <a href="classes/CampaignMonitor/SubscriberClick.html#M000011">new (CampaignMonitor::SubscriberClick)</a><br />
42
+ <a href="classes/CampaignMonitor/SubscriberBounce.html#M000020">new (CampaignMonitor::SubscriberBounce)</a><br />
43
+ <a href="classes/CampaignMonitor/Result.html#M000021">new (CampaignMonitor::Result)</a><br />
44
+ <a href="classes/CampaignMonitor/List.html#M000022">new (CampaignMonitor::List)</a><br />
45
+ <a href="classes/CampaignMonitor.html#M000002">new (CampaignMonitor)</a><br />
46
+ <a href="classes/CampaignMonitor/Subscriber.html#M000013">new (CampaignMonitor::Subscriber)</a><br />
47
+ <a href="classes/CampaignMonitor/Campaign.html#M000037">number_bounced (CampaignMonitor::Campaign)</a><br />
48
+ <a href="classes/CampaignMonitor/Campaign.html#M000035">number_clicks (CampaignMonitor::Campaign)</a><br />
49
+ <a href="classes/CampaignMonitor/Campaign.html#M000034">number_opened (CampaignMonitor::Campaign)</a><br />
50
+ <a href="classes/CampaignMonitor/Campaign.html#M000033">number_recipients (CampaignMonitor::Campaign)</a><br />
51
+ <a href="classes/CampaignMonitor/Campaign.html#M000036">number_unsubscribed (CampaignMonitor::Campaign)</a><br />
52
+ <a href="classes/CampaignMonitor/Campaign.html#M000029">opens (CampaignMonitor::Campaign)</a><br />
53
+ <a href="classes/CampaignMonitor/List.html#M000024">remove_subscriber (CampaignMonitor::List)</a><br />
54
+ <a href="classes/CampaignMonitor.html#M000003">request (CampaignMonitor)</a><br />
55
+ <a href="classes/CampaignMonitor.html#M000004">request_url (CampaignMonitor)</a><br />
56
+ <a href="classes/CampaignMonitorTest.html#M000001">setup (CampaignMonitorTest)</a><br />
57
+ <a href="classes/CampaignMonitor/Subscriber.html#M000015">unsubscribe (CampaignMonitor::Subscriber)</a><br />
58
+ <a href="classes/CampaignMonitor/List.html#M000026">unsubscribed (CampaignMonitor::List)</a><br />
59
+ <a href="classes/CampaignMonitor/Campaign.html#M000032">unsubscribes (CampaignMonitor::Campaign)</a><br />
60
+ </div>
61
+ </div>
62
+ </body>
63
+ </html>
data/doc/index.html ADDED
@@ -0,0 +1,24 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
5
+
6
+ <!--
7
+
8
+ RDoc Documentation
9
+
10
+ -->
11
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
12
+ <head>
13
+ <title>RDoc Documentation</title>
14
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
15
+ </head>
16
+ <frameset rows="20%, 80%">
17
+ <frameset cols="25%,35%,45%">
18
+ <frame src="fr_file_index.html" title="Files" name="Files" />
19
+ <frame src="fr_class_index.html" name="Classes" />
20
+ <frame src="fr_method_index.html" name="Methods" />
21
+ </frameset>
22
+ <frame src="files/lib/campaign_monitor_rb.html" name="docwin" />
23
+ </frameset>
24
+ </html>
@@ -0,0 +1,208 @@
1
+
2
+ body {
3
+ font-family: Verdana,Arial,Helvetica,sans-serif;
4
+ font-size: 90%;
5
+ margin: 0;
6
+ margin-left: 40px;
7
+ padding: 0;
8
+ background: white;
9
+ }
10
+
11
+ h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
12
+ h1 { font-size: 150%; }
13
+ h2,h3,h4 { margin-top: 1em; }
14
+
15
+ a { background: #eef; color: #039; text-decoration: none; }
16
+ a:hover { background: #039; color: #eef; }
17
+
18
+ /* Override the base stylesheet's Anchor inside a table cell */
19
+ td > a {
20
+ background: transparent;
21
+ color: #039;
22
+ text-decoration: none;
23
+ }
24
+
25
+ /* and inside a section title */
26
+ .section-title > a {
27
+ background: transparent;
28
+ color: #eee;
29
+ text-decoration: none;
30
+ }
31
+
32
+ /* === Structural elements =================================== */
33
+
34
+ div#index {
35
+ margin: 0;
36
+ margin-left: -40px;
37
+ padding: 0;
38
+ font-size: 90%;
39
+ }
40
+
41
+
42
+ div#index a {
43
+ margin-left: 0.7em;
44
+ }
45
+
46
+ div#index .section-bar {
47
+ margin-left: 0px;
48
+ padding-left: 0.7em;
49
+ background: #ccc;
50
+ font-size: small;
51
+ }
52
+
53
+
54
+ div#classHeader, div#fileHeader {
55
+ width: auto;
56
+ color: white;
57
+ padding: 0.5em 1.5em 0.5em 1.5em;
58
+ margin: 0;
59
+ margin-left: -40px;
60
+ border-bottom: 3px solid #006;
61
+ }
62
+
63
+ div#classHeader a, div#fileHeader a {
64
+ background: inherit;
65
+ color: white;
66
+ }
67
+
68
+ div#classHeader td, div#fileHeader td {
69
+ background: inherit;
70
+ color: white;
71
+ }
72
+
73
+
74
+ div#fileHeader {
75
+ background: #057;
76
+ }
77
+
78
+ div#classHeader {
79
+ background: #048;
80
+ }
81
+
82
+
83
+ .class-name-in-header {
84
+ font-size: 180%;
85
+ font-weight: bold;
86
+ }
87
+
88
+
89
+ div#bodyContent {
90
+ padding: 0 1.5em 0 1.5em;
91
+ }
92
+
93
+ div#description {
94
+ padding: 0.5em 1.5em;
95
+ background: #efefef;
96
+ border: 1px dotted #999;
97
+ }
98
+
99
+ div#description h1,h2,h3,h4,h5,h6 {
100
+ color: #125;;
101
+ background: transparent;
102
+ }
103
+
104
+ div#validator-badges {
105
+ text-align: center;
106
+ }
107
+ div#validator-badges img { border: 0; }
108
+
109
+ div#copyright {
110
+ color: #333;
111
+ background: #efefef;
112
+ font: 0.75em sans-serif;
113
+ margin-top: 5em;
114
+ margin-bottom: 0;
115
+ padding: 0.5em 2em;
116
+ }
117
+
118
+
119
+ /* === Classes =================================== */
120
+
121
+ table.header-table {
122
+ color: white;
123
+ font-size: small;
124
+ }
125
+
126
+ .type-note {
127
+ font-size: small;
128
+ color: #DEDEDE;
129
+ }
130
+
131
+ .xxsection-bar {
132
+ background: #eee;
133
+ color: #333;
134
+ padding: 3px;
135
+ }
136
+
137
+ .section-bar {
138
+ color: #333;
139
+ border-bottom: 1px solid #999;
140
+ margin-left: -20px;
141
+ }
142
+
143
+
144
+ .section-title {
145
+ background: #79a;
146
+ color: #eee;
147
+ padding: 3px;
148
+ margin-top: 2em;
149
+ margin-left: -30px;
150
+ border: 1px solid #999;
151
+ }
152
+
153
+ .top-aligned-row { vertical-align: top }
154
+ .bottom-aligned-row { vertical-align: bottom }
155
+
156
+ /* --- Context section classes ----------------------- */
157
+
158
+ .context-row { }
159
+ .context-item-name { font-family: monospace; font-weight: bold; color: black; }
160
+ .context-item-value { font-size: small; color: #448; }
161
+ .context-item-desc { color: #333; padding-left: 2em; }
162
+
163
+ /* --- Method classes -------------------------- */
164
+ .method-detail {
165
+ background: #efefef;
166
+ padding: 0;
167
+ margin-top: 0.5em;
168
+ margin-bottom: 1em;
169
+ border: 1px dotted #ccc;
170
+ }
171
+ .method-heading {
172
+ color: black;
173
+ background: #ccc;
174
+ border-bottom: 1px solid #666;
175
+ padding: 0.2em 0.5em 0 0.5em;
176
+ }
177
+ .method-signature { color: black; background: inherit; }
178
+ .method-name { font-weight: bold; }
179
+ .method-args { font-style: italic; }
180
+ .method-description { padding: 0 0.5em 0 0.5em; }
181
+
182
+ /* --- Source code sections -------------------- */
183
+
184
+ a.source-toggle { font-size: 90%; }
185
+ div.method-source-code {
186
+ background: #262626;
187
+ color: #ffdead;
188
+ margin: 1em;
189
+ padding: 0.5em;
190
+ border: 1px dashed #999;
191
+ overflow: hidden;
192
+ }
193
+
194
+ div.method-source-code pre { color: #ffdead; overflow: hidden; }
195
+
196
+ /* --- Ruby keyword styles --------------------- */
197
+
198
+ .standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
199
+
200
+ .ruby-constant { color: #7fffd4; background: transparent; }
201
+ .ruby-keyword { color: #00ffff; background: transparent; }
202
+ .ruby-ivar { color: #eedd82; background: transparent; }
203
+ .ruby-operator { color: #00ffee; background: transparent; }
204
+ .ruby-identifier { color: #ffdead; background: transparent; }
205
+ .ruby-node { color: #ffa07a; background: transparent; }
206
+ .ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
207
+ .ruby-regexp { color: #ffa07a; background: transparent; }
208
+ .ruby-value { color: #7fffd4; background: transparent; }
@@ -0,0 +1,503 @@
1
+ # CampaignMonitor
2
+ # A wrapper class to access the Campaign Monitor API. Written using the wonderful
3
+ # Flickr interface by Scott Raymond as a guide on how to access remote web services
4
+ #
5
+ # For more information on the Campaign Monitor API, visit http://campaignmonitor.com/api
6
+ #
7
+ # Author:: Jordan Brock <jordan@spintech.com.au>
8
+ # Copyright:: Copyright (c) 2006 Jordan Brock <jordan@spintech.com.au>
9
+ # License:: MIT <http://www.opensource.org/licenses/mit-license.php>
10
+ #
11
+ # USAGE:
12
+ # require 'campaign_monitor'
13
+ # cm = CampaignMonitor.new(API_KEY) # creates a CampaignMonitor object
14
+ # # Can set CAMPAIGN_MONITOR_API_KEY in environment.rb
15
+ # cm.clients # Returns an array of clients associated with
16
+ # # the user account
17
+ # cm.campaigns(client_id)
18
+ # cm.lists(client_id)
19
+ # cm.add_subscriber(list_id, email, name)
20
+ #
21
+ # CLIENT
22
+ # client = Client.new(client_id)
23
+ # client.lists
24
+ # client.campaigns
25
+ #
26
+ # LIST
27
+ # list = List.new(list_id)
28
+ # list.add_subscriber(email, name)
29
+ # list.remove_subscriber(email)
30
+ # list.active_subscribers(date)
31
+ # list.unsubscribed(date)
32
+ # list.bounced(date)
33
+ #
34
+ # CAMPAIGN
35
+ # campaign = Campaign.new(campaign_id)
36
+ # campaign.clicks
37
+ # campaign.opens
38
+ # campaign.bounces
39
+ # campaign.unsubscribes
40
+ # campaign.number_recipients
41
+ # campaign.number_clicks
42
+ # campaign.number_opens
43
+ # campaign.number_bounces
44
+ # campaign.number_unsubscribes
45
+ #
46
+ #
47
+ # SUBSCRIBER
48
+ # subscriber = Subscriber.new(email)
49
+ # subscriber.add(list_id)
50
+ # subscriber.unsubscribe(list_id)
51
+ #
52
+ # Data Types
53
+ # SubscriberBounce
54
+ # SubscriberClick
55
+ # SubscriberOpen
56
+ # SubscriberUnsubscribe
57
+ # Result
58
+ #
59
+
60
+ require 'cgi'
61
+ require 'net/http'
62
+
63
+ class CampaignMonitor
64
+ # Replace this API key with your own (http://www.campaignmonitor.com/api/)
65
+ def initialize(api_key=CAMPAIGN_MONITOR_API_KEY)
66
+ @api_key = api_key
67
+ @host = 'http://app.campaignmonitor.com'
68
+ @api = '/api/api.asmx/'
69
+ end
70
+
71
+ # Takes a CampaignMonitor API method name and set of parameters;
72
+ # returns an XmlSimple object with the response
73
+ def request(method, *params)
74
+ response = XmlSimple.xml_in(http_get(request_url(method, params)), { 'ForceArray' => false, 'ForceArray' => %r(List$|Campaign$|Subscriber$|Client$|SubscriberOpen$|SubscriberUnsubscribe$|SubscriberClick$|SubscriberBounce$), 'NoAttr' => true })
75
+ response
76
+ end
77
+
78
+ # Takes a CampaignMonitor API method name and set of parameters; returns the correct URL for the REST API.
79
+ def request_url(method, *params)
80
+ url = "#{@host}#{@api}/#{method}?ApiKey=#{@api_key}"
81
+ params[0][0].each_key do |key| url += "&#{key}=" + CGI::escape(params[0][0][key].to_s) end if params[0][0]
82
+ url
83
+ end
84
+
85
+ # Does an HTTP GET on a given URL and returns the response body
86
+ def http_get(url)
87
+ Net::HTTP.get_response(URI.parse(url)).body.to_s
88
+ end
89
+
90
+ # By overriding the method_missing method, it is possible to easily support all of the methods
91
+ # available in the API
92
+ def method_missing(method_id, *params)
93
+ request(method_id.id2name.gsub(/_/, '.'), params[0])
94
+ end
95
+
96
+ # Returns an array of Client objects associated with the API Key
97
+ #
98
+ # Example
99
+ # @cm = CampaignMonitor.new()
100
+ # @clients = @cm.clients
101
+ #
102
+ # for client in @clients
103
+ # puts client.name
104
+ # end
105
+ def clients
106
+ response = User_GetClients()
107
+ unless response["Code"].to_i != 0
108
+ response["Client"].collect{|c| Client.new(c["ClientID"].to_i, c["Name"])}
109
+ else
110
+ raise response["Code"] + " - " + response["Message"]
111
+ end
112
+ end
113
+
114
+ # Returns an array of Campaign objects associated with the specified Client ID
115
+ #
116
+ # Example
117
+ # @cm = CampaignMonitor.new()
118
+ # @campaigns = @cm.campaigns(12345)
119
+ #
120
+ # for campaign in @campaigns
121
+ # puts campaign.subject
122
+ # end
123
+ def campaigns(client_id)
124
+ response = Client_GetCampaigns("ClientID" => client_id)
125
+ unless response["Code"].to_i != 0
126
+ response["Campaign"].collect{|c| Campaign.new(c["CampaignID"].to_i, c["Subject"], c["SentDate"], c["TotalRecipients"].to_i)}
127
+ else
128
+ raise response["Code"] + " - " + response["Message"]
129
+ end
130
+ end
131
+
132
+ # Returns an array of Subscriber Lists for the specified Client ID
133
+ #
134
+ # Example
135
+ # @cm = CampaignMonitor.new()
136
+ # @lists = @cm.lists(12345)
137
+ #
138
+ # for list in @lists
139
+ # puts list.name
140
+ # end
141
+ def lists(client_id)
142
+ response = Client_GetLists("ClientID" => client_id)
143
+ unless response["Code"].to_i != 0
144
+ response["List"].collect{|l| List.new(l["ListID"].to_i, l["Name"])}
145
+ else
146
+ raise response["Code"] + " - " + response["Message"]
147
+ end
148
+ end
149
+
150
+ # A quick method of adding a subscriber to a list. Returns a Result object
151
+ #
152
+ # Example
153
+ # @cm = CampaignMonitor.new()
154
+ # result = @cm.add_subscriber(12345, "ralph.wiggum@simpsons.net", "Ralph Wiggum")
155
+ #
156
+ # if result.code == 0
157
+ # puts "Subscriber Added to List"
158
+ # end
159
+ def add_subscriber(list_id, email, name)
160
+ response = Subscriber_Add("ListID" => list_id, "Email" => email, "Name" => name)
161
+ Result.new(response["Message"], response["Code"].to_i)
162
+ end
163
+
164
+ # Provides access to the lists and campaigns associated with a client
165
+ class Client
166
+ attr_reader :id, :name, :cm_client
167
+
168
+ # Example
169
+ # @client = new Client(12345)
170
+ def initialize(id, name=nil)
171
+ @id = id
172
+ @name = name
173
+ @cm_client = CampaignMonitor.new
174
+ end
175
+
176
+ # Example
177
+ # @client = new Client(12345)
178
+ # @lists = @client.lists
179
+ #
180
+ # for list in @lists
181
+ # puts list.name
182
+ # end
183
+ def lists
184
+ response = @cm_client.Client_GetLists("ClientID" => @id)
185
+ unless response["Code"].to_i != 0
186
+ response["List"].collect{|l| List.new(l["ListID"].to_i, l["Name"])}
187
+ else
188
+ raise response["Code"] + " - " + response["Message"]
189
+ end
190
+ end
191
+
192
+ # Example
193
+ # @client = new Client(12345)
194
+ # @campaigns = @client.campaigns
195
+ #
196
+ # for campaign in @campaigns
197
+ # puts campaign.subject
198
+ # end
199
+ def campaigns
200
+ response = @cm_client.Client_GetCampaigns("ClientID" => @id)
201
+ unless response["Code"].to_i != 0
202
+ response["Campaign"].collect{|c| Campaign.new(c["CampaignID"].to_i, c["Subject"], c["SentDate"], c["TotalRecipients"].to_i)}
203
+ else
204
+ raise response["Code"] + " - " + response["Message"]
205
+ end
206
+ end
207
+ end
208
+
209
+ # Provides access to the subscribers and info about subscribers
210
+ # associated with a Mailing List
211
+ class List
212
+ attr_reader :id, :name, :cm_client
213
+
214
+ # Example
215
+ # @list = new List(12345)
216
+ def initialize(id=nil, name=nil)
217
+ @id = id
218
+ @name = name
219
+ @cm_client = CampaignMonitor.new
220
+ end
221
+
222
+ # Example
223
+ # @list = new List(12345)
224
+ # result = @list.add_subscriber("ralph.wiggum@simpsons.net")
225
+ #
226
+ # if result.code == 0
227
+ # puts "Added Subscriber"
228
+ # end
229
+ def add_subscriber(email, name = nil)
230
+ response = @cm_client.Subscriber_Add("ListID" => @id, "Email" => email, "Name" => name)
231
+ Result.new(response["Message"], response["Code"].to_i)
232
+ end
233
+
234
+ # Example
235
+ # @list = new List(12345)
236
+ # result = @list.remove_subscriber("ralph.wiggum@simpsons.net")
237
+ #
238
+ # if result.code == 0
239
+ # puts "Deleted Subscriber"
240
+ # end
241
+ def remove_subscriber(email)
242
+ response = @cm_client.Subscriber_Unsubscribe("ListID" => @id, "Email" => email)
243
+ Result.new(response["Message"], response["Code"].to_i)
244
+ end
245
+
246
+ # Example
247
+ # current_date = DateTime.new
248
+ # @list = new List(12345)
249
+ # @subscribers = @list.active_subscribers(current_date)
250
+ #
251
+ # for subscriber in @subscribers
252
+ # puts subscriber.email
253
+ # end
254
+ def active_subscribers(date)
255
+ response = @cm_client.Subscribers_GetActive('ListID' => @id, "Date" => date.strftime("%Y-%m-%d %H:%M:%S"))
256
+ unless response["Code"].to_i != 0
257
+ response["Subscriber"].collect{|s| Subscriber.new(s["EmailAddress"], s["Name"], s["Date"])}
258
+ else
259
+ raise response["Code"] + " - " + response["Message"]
260
+ end
261
+ end
262
+
263
+ # Example
264
+ # current_date = DateTime.new
265
+ # @list = new List(12345)
266
+ # @subscribers = @list.unsubscribed(current_date)
267
+ #
268
+ # for subscriber in @subscribers
269
+ # puts subscriber.email
270
+ # end
271
+ def unsubscribed(date)
272
+ response = @cm_client.Subscribers_GetUnsubscribed('ListID' => @id, 'Date' => date.strftime("%Y-%m-%d %H:%M:%S"))
273
+ unless response["Code"].to_i != 0
274
+ response["Subscriber"].collect{|s| Subscriber.new(s["EmailAddress"], s["Name"], s["Date"])}
275
+ else
276
+ raise response["Code"] + " - " + response["Message"]
277
+ end
278
+ end
279
+
280
+ # Example
281
+ # current_date = DateTime.new
282
+ # @list = new List(12345)
283
+ # @subscribers = @list.bounced(current_date)
284
+ #
285
+ # for subscriber in @subscribers
286
+ # puts subscriber.email
287
+ # end
288
+ def bounced(date)
289
+ response = @cm_client.Subscribers_GetBounced('ListID' => @id, 'Date' => date.strftime("%Y-%m-%d %H:%M:%S"))
290
+ unless response["Code"].to_i != 0
291
+ response["Subscriber"].collect{|s| Subscriber.new(s["EmailAddress"], s["Name"], s["Date"])}
292
+ else
293
+ raise response["Code"] + " - " + response["Message"]
294
+ end
295
+ end
296
+
297
+ end
298
+
299
+ # Provides access to the information about a campaign
300
+ class Campaign
301
+ attr_reader :id, :subject, :sent_date, :total_recipients
302
+
303
+ def initialize(id=nil, subject=nil, sent_date=nil, total_recipients=nil)
304
+ @id = id
305
+ @subject = subject
306
+ @sent_date = sent_date
307
+ @total_recipients = total_recipients
308
+ @cm_client = CampaignMonitor.new
309
+ end
310
+
311
+ # Example
312
+ # @campaign = Campaign.new(12345)
313
+ # @subscriber_opens = @campaign.opens
314
+ #
315
+ # for subscriber in @subscriber_opens
316
+ # puts subscriber.email
317
+ # end
318
+ def opens
319
+ response = @cm_client.Campaign_GetOpens("CampaignID" => @id)
320
+ unless response["Code"].to_i != 0
321
+ response["SubscriberOpen"].collect{|s| SubscriberOpen.new(s["EmailAddress"], s["ListID"].to_i, s["NumberOfOpens"])}
322
+ else
323
+ raise response["Code"] + " - " + response["Message"]
324
+ end
325
+ end
326
+
327
+ # Example
328
+ # @campaign = Campaign.new(12345)
329
+ # @subscriber_bounces = @campaign.bounces
330
+ #
331
+ # for subscriber in @subscriber_bounces
332
+ # puts subscriber.email
333
+ # end
334
+ def bounces
335
+ response = @cm_client.Campaign_GetBounces("CampaignID"=> @id)
336
+ unless response["Code"].to_i != 0
337
+ response["SubscriberBounce"].collect{|s| SubscriberBounce.new(s["EmailAddress"], s["ListID"].to_i, s["BounceType"])}
338
+ else
339
+ raise response["Code"] + " - " + response["Message"]
340
+ end
341
+ end
342
+
343
+ # Example
344
+ # @campaign = Campaign.new(12345)
345
+ # @subscriber_clicks = @campaign.clicks
346
+ #
347
+ # for subscriber in @subscriber_clicks
348
+ # puts subscriber.email
349
+ # end
350
+ def clicks
351
+ response = @cm_client.Campaign_GetSubscriberClicks("CampaignID" => @id)
352
+ unless response["Code"].to_i != 0
353
+ response["SubscriberClick"].collect{|s| SubscriberClick.new(s["EmailAddress"], s["ListID"].to_i, s["ClickedLinks"])}
354
+ else
355
+ raise response["Code"] + " - " + response["Message"]
356
+ end
357
+ end
358
+
359
+ # Example
360
+ # @campaign = Campaign.new(12345)
361
+ # @subscriber_unsubscribes = @campaign.unsubscribes
362
+ #
363
+ # for subscriber in @subscriber_unsubscribes
364
+ # puts subscriber.email
365
+ # end
366
+ def unsubscribes
367
+ response = @cm_client.Campaign_GetUnsubscribes("CampaignID" => @id)
368
+ unless response["Code"].to_i != 0
369
+ response["SubscriberUnsubscribe"].collect{|s| SubscriberUnsubscribe.new(s["EmailAddress"], s["ListID"].to_i)}
370
+ else
371
+ raise response["Code"] + " - " + response["Message"]
372
+ end
373
+ end
374
+
375
+ # Example
376
+ # @campaign = Campaign.new(12345)
377
+ # puts @campaign.number_recipients
378
+ def number_recipients
379
+ @number_recipients.nil? ? getInfo.number_recipients : @number_recipients
380
+ end
381
+
382
+ # Example
383
+ # @campaign = Campaign.new(12345)
384
+ # puts @campaign.number_opened
385
+ def number_opened
386
+ @number_opened.nil? ? getInfo.number_opened : @number_opened
387
+ end
388
+
389
+ # Example
390
+ # @campaign = Campaign.new(12345)
391
+ # puts @campaign.number_clicks
392
+ def number_clicks
393
+ @number_clicks.nil? ? getInfo.number_clicks : @number_clicks
394
+ end
395
+
396
+ # Example
397
+ # @campaign = Campaign.new(12345)
398
+ # puts @campaign.number_unsubscribed
399
+ def number_unsubscribed
400
+ @number_unsubscribed.nil? ? getInfo.number_unsubscribed : @number_unsubscribed
401
+ end
402
+
403
+ # Example
404
+ # @campaign = Campaign.new(12345)
405
+ # puts @campaign.number_bounced
406
+ def number_bounced
407
+ @number_bounced.nil? ? getInfo.number_bounced : @number_bounced
408
+ end
409
+
410
+ private
411
+ def getInfo
412
+ info = @cm_client.Campaign_GetSummary('CampaignID'=>@id)
413
+ @title = info['title']
414
+ @number_recipients = info["Recipients"].to_i
415
+ @number_opened = info["TotalOpened"].to_i
416
+ @number_clicks = info["Click"].to_i
417
+ @number_unsubscribed = info["Unsubscribed"].to_i
418
+ @number_bounced = info["Bounced"].to_i
419
+ self
420
+ end
421
+ end
422
+
423
+ # Provides the ability to add/remove subscribers from a list
424
+ class Subscriber
425
+ attr_accessor :email_address, :name, :date_subscribed
426
+
427
+ def initialize(email_address, name=nil, date=nil)
428
+ @email_address = email_address
429
+ @name = name
430
+ @date_subscribed = date_subscribed
431
+ @cm_client = CampaignMonitor.new
432
+ end
433
+
434
+ # Example
435
+ # @subscriber = Subscriber.new("ralph.wiggum@simpsons.net")
436
+ # @subscriber.add(12345)
437
+ def add(list_id)
438
+ response = @cm_client.Subscriber_Add("ListID" => list_id, "Email" => @email_address, "Name" => @name)
439
+ Result.new(response["Message"], response["Code"].to_i)
440
+ end
441
+
442
+ # Example
443
+ # @subscriber = Subscriber.new("ralph.wiggum@simpsons.net")
444
+ # @subscriber.unsubscribe(12345)
445
+ def unsubscribe(list_id)
446
+ response = @cm_client.Subscriber_Unsubscribe("ListID" => list_id, "Email" => @email_address)
447
+ Result.new(response["Message"], response["Code"].to_i)
448
+ end
449
+ end
450
+
451
+ # Encapsulates
452
+ class SubscriberBounce
453
+ attr_reader :email_address, :bounce_type, :list_id
454
+
455
+ def initialize(email_address, list_id, bounce_type)
456
+ @email_address = email_address
457
+ @bounce_type = bounce_type
458
+ @list_id = list_id
459
+ end
460
+ end
461
+
462
+ # Encapsulates
463
+ class SubscriberOpen
464
+ attr_reader :email_address, :list_id, :opens
465
+
466
+ def initialize(email_address, list_id, opens)
467
+ @email_address = email_address
468
+ @list_id = list_id
469
+ @opens = opens
470
+ end
471
+ end
472
+
473
+ # Encapsulates
474
+ class SubscriberClick
475
+ attr_reader :email_address, :list_id, :clicked_links
476
+
477
+ def initialize(email_address, list_id, clicked_links)
478
+ @email_address = email_address
479
+ @list_id = list_id
480
+ @clicked_links = clicked_links
481
+ end
482
+ end
483
+
484
+ # Encapsulates
485
+ class SubscriberUnsubscribe
486
+ attr_reader :email_address, :list_id
487
+
488
+ def initialize(email_address, list_id)
489
+ @email_address = email_address
490
+ @list_id = list_id
491
+ end
492
+ end
493
+
494
+ # Encapsulates the response received from the CampaignMonitor webservice.
495
+ class Result
496
+ attr_reader :message, :code
497
+
498
+ def initialize(message, code)
499
+ @message = message
500
+ @code = code
501
+ end
502
+ end
503
+ end