textmagic 0.3.3 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/README.rdoc +2 -2
- data/Rakefile +22 -21
- data/VERSION.yml +3 -2
- data/lib/api.rb +52 -52
- data/lib/charset.rb +3 -1
- data/lib/error.rb +2 -2
- data/lib/executor.rb +6 -6
- data/lib/response.rb +20 -20
- data/lib/textmagic.rb +3 -3
- data/test/test_api.rb +69 -67
- data/test/test_charset.rb +16 -15
- data/test/test_error.rb +5 -5
- data/test/test_executor.rb +17 -18
- data/test/test_helper.rb +8 -12
- data/test/test_response.rb +75 -75
- data/test/test_validation.rb +26 -27
- data/textmagic.gemspec +24 -17
- metadata +77 -25
data/.gitignore
CHANGED
data/README.rdoc
CHANGED
@@ -145,8 +145,8 @@ to all of the gem's features. Run
|
|
145
145
|
|
146
146
|
from your console to see help on its usage.
|
147
147
|
|
148
|
-
<i>Note: This has only been tested on a Mac. If you have any troubles
|
149
|
-
|
148
|
+
<i>Note: This has only been tested on a Mac with Ruby 1.8.7 and 1.9.1. If you have any troubles
|
149
|
+
using this gem, contact the author (or submit a patch).</i>
|
150
150
|
|
151
151
|
== Copyright
|
152
152
|
|
data/Rakefile
CHANGED
@@ -1,9 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "rake"
|
5
|
+
require "yaml"
|
6
|
+
require "rake/testtask"
|
7
|
+
require "rake/rdoctask"
|
4
8
|
|
5
9
|
begin
|
6
|
-
require
|
10
|
+
require "jeweler"
|
7
11
|
Jeweler::Tasks.new do |gem|
|
8
12
|
gem.name = "textmagic"
|
9
13
|
gem.summary = %Q{Ruby interface to the TextMagic's Bulk SMS Gateway}
|
@@ -17,10 +21,11 @@ begin
|
|
17
21
|
gem.homepage = "http://github.com/bobes/textmagic"
|
18
22
|
gem.authors = ["Vladimír Bobeš Tužinský"]
|
19
23
|
gem.rubyforge_project = "textmagic"
|
20
|
-
gem.add_runtime_dependency "httparty", ">= 0.
|
21
|
-
gem.add_development_dependency "mocha", ">= 0.9.
|
22
|
-
gem.add_development_dependency "
|
23
|
-
gem.add_development_dependency "
|
24
|
+
gem.add_runtime_dependency "httparty", ">= 0.5.2"
|
25
|
+
gem.add_development_dependency "mocha", ">= 0.9.8"
|
26
|
+
gem.add_development_dependency "shoulda", ">= 2.10.3"
|
27
|
+
gem.add_development_dependency "fakeweb", ">= 1.2.8"
|
28
|
+
gem.add_development_dependency "mcmire-matchy", ">= 0.5.2"
|
24
29
|
end
|
25
30
|
|
26
31
|
Jeweler::RubyforgeTasks.new
|
@@ -28,18 +33,18 @@ rescue LoadError
|
|
28
33
|
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
29
34
|
end
|
30
35
|
|
31
|
-
require 'rake/testtask'
|
32
36
|
Rake::TestTask.new(:test) do |test|
|
33
|
-
test.libs <<
|
34
|
-
test.pattern =
|
37
|
+
test.libs << "lib" << "test"
|
38
|
+
test.pattern = "test/**/test_*.rb"
|
35
39
|
test.verbose = true
|
36
40
|
end
|
41
|
+
task :default => :test
|
37
42
|
|
38
43
|
begin
|
39
|
-
require
|
44
|
+
require "rcov/rcovtask"
|
40
45
|
Rcov::RcovTask.new do |test|
|
41
|
-
test.libs <<
|
42
|
-
test.pattern =
|
46
|
+
test.libs << "test"
|
47
|
+
test.pattern = "test/**/test_*.rb"
|
43
48
|
test.verbose = true
|
44
49
|
end
|
45
50
|
rescue LoadError
|
@@ -48,13 +53,9 @@ rescue LoadError
|
|
48
53
|
end
|
49
54
|
end
|
50
55
|
|
51
|
-
|
52
|
-
task :default => :test
|
53
|
-
|
54
|
-
require 'rake/rdoctask'
|
55
56
|
Rake::RDocTask.new do |rdoc|
|
56
|
-
if File.exist?(
|
57
|
-
config = YAML.load(File.read(
|
57
|
+
if File.exist?("VERSION.yml")
|
58
|
+
config = YAML.load(File.read("VERSION.yml"))
|
58
59
|
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
59
60
|
else
|
60
61
|
version = ""
|
@@ -88,7 +89,7 @@ task :doc => :rerdoc do
|
|
88
89
|
git push origin gh-pages
|
89
90
|
EOS
|
90
91
|
|
91
|
-
system cmd.split(/\n\s*/).join(
|
92
|
+
system cmd.split(/\n\s*/).join(" && ")
|
92
93
|
|
93
94
|
system <<-EOS
|
94
95
|
echo 'Checking out master'
|
data/VERSION.yml
CHANGED
data/lib/api.rb
CHANGED
@@ -12,7 +12,7 @@ module TextMagic
|
|
12
12
|
#
|
13
13
|
# Example usage:
|
14
14
|
#
|
15
|
-
# api = TextMagic::API.new(
|
15
|
+
# api = TextMagic::API.new("fred", "secret")
|
16
16
|
def initialize(username, password)
|
17
17
|
@username = username
|
18
18
|
@password = password
|
@@ -30,7 +30,7 @@ module TextMagic
|
|
30
30
|
# api.account.balance
|
31
31
|
# # => 314.15
|
32
32
|
def account
|
33
|
-
hash = Executor.execute(
|
33
|
+
hash = Executor.execute("account", @username, @password)
|
34
34
|
TextMagic::API::Response.account(hash)
|
35
35
|
end
|
36
36
|
|
@@ -58,43 +58,43 @@ module TextMagic
|
|
58
58
|
#
|
59
59
|
# Example usage:
|
60
60
|
#
|
61
|
-
# api.send(
|
62
|
-
# # =>
|
63
|
-
# response = api.send(
|
64
|
-
# # => {
|
61
|
+
# api.send("Hi Wilma", "999314159265")
|
62
|
+
# # => "141421"
|
63
|
+
# response = api.send("Hello everybody", "999314159265", "999271828182", :max_length => 2)
|
64
|
+
# # => { "999314159265" => "141421", "999271828182" => "173205" }
|
65
65
|
# response.parts_count
|
66
66
|
# # => 1
|
67
67
|
#
|
68
68
|
# Multiple phone numbers can be supplied as an array or as a list of arguments:
|
69
69
|
#
|
70
|
-
# api.send(
|
71
|
-
# api.send(
|
70
|
+
# api.send("Hello everybody", ["999314159265", "999271828182"])
|
71
|
+
# api.send("Hello everybody", "999314159265", "999271828182")
|
72
72
|
#
|
73
73
|
# If you want to send a message to a single phone number but still
|
74
74
|
# want to get a hash response, put the phone number in an array:
|
75
75
|
#
|
76
|
-
# api.send(
|
76
|
+
# api.send("Hi Barney", ["999271828182"])
|
77
77
|
#
|
78
78
|
# Postponed sending:
|
79
79
|
#
|
80
|
-
# api.send(
|
80
|
+
# api.send("Two hours later", "999314159265", :send_time => Time.now.to_i + 7200)
|
81
81
|
def send(text, *args)
|
82
|
-
raise Error.new(1,
|
82
|
+
raise Error.new(1, "Message text is empty") if text.nil? || text.blank?
|
83
83
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
84
84
|
unicode = API.is_unicode(text)
|
85
85
|
options[:unicode] = case options[:unicode]
|
86
|
-
when 1, true
|
87
|
-
when 0, false
|
88
|
-
when nil
|
86
|
+
when 1, true then 1
|
87
|
+
when 0, false then 0
|
88
|
+
when nil then unicode ? 1 : 0
|
89
89
|
else raise Error.new(10, "Wrong parameter value #{options[:unicode]} for parameter unicode")
|
90
90
|
end
|
91
|
-
raise Error.new(6,
|
92
|
-
raise Error.new(7,
|
91
|
+
raise Error.new(6, "Message contains invalid characters") if unicode && options[:unicode] == 0
|
92
|
+
raise Error.new(7, "Message too long") unless API.validate_text_length(text, unicode)
|
93
93
|
single = args.size == 1 && args.first.is_a?(String)
|
94
94
|
phones = args.flatten
|
95
|
-
raise Error.new(9,
|
95
|
+
raise Error.new(9, "Invalid phone number format") unless API.validate_phones(phones)
|
96
96
|
options[:send_time] = options[:send_time].to_i if options[:send_time]
|
97
|
-
hash = Executor.execute(
|
97
|
+
hash = Executor.execute("send", @username, @password, options.merge(:text => text, :phone => phones.join(",")))
|
98
98
|
TextMagic::API::Response.send(hash, single)
|
99
99
|
end
|
100
100
|
|
@@ -111,37 +111,37 @@ module TextMagic
|
|
111
111
|
#
|
112
112
|
# Example usage:
|
113
113
|
#
|
114
|
-
# status = api.message_status(
|
115
|
-
# # =>
|
114
|
+
# status = api.message_status("141421")
|
115
|
+
# # => "d"
|
116
116
|
# status.completed_time
|
117
117
|
# # => Fri May 22 10:10:18 +0200 2009
|
118
118
|
#
|
119
119
|
# Example with multiple ids:
|
120
120
|
#
|
121
|
-
# statuses = api.message_status(
|
122
|
-
# # => {
|
123
|
-
# statuses[
|
124
|
-
# # =>
|
125
|
-
# statuses[
|
121
|
+
# statuses = api.message_status("141421", "173205")
|
122
|
+
# # => { "141421" => "r", "173205" => "d" }
|
123
|
+
# statuses["141421"].text
|
124
|
+
# # => "Hi Wilma"
|
125
|
+
# statuses["173205"].created_time
|
126
126
|
# # => Thu May 28 16:41:45 +0200 2009
|
127
127
|
#
|
128
128
|
# Multiple ids can be supplied as an array or as a list of arguments:
|
129
129
|
#
|
130
|
-
# api.send(
|
131
|
-
# api.send(
|
130
|
+
# api.send("Hello everybody", ["999314159265", "999271828182"])
|
131
|
+
# api.send("Hello everybody", "999314159265", "999271828182")
|
132
132
|
#
|
133
133
|
# If you want to request status for a single message but still want to get
|
134
134
|
# a hash response, put the id in an array:
|
135
135
|
#
|
136
|
-
# api.message_status([
|
136
|
+
# api.message_status(["141421"])
|
137
137
|
#
|
138
138
|
# <b>It is strongly encouraged to setup callbacks to receive updates on message status
|
139
139
|
# instead of using this method.</b>
|
140
140
|
def message_status(*ids)
|
141
141
|
single = ids.size == 1 && ids.first.is_a?(String)
|
142
142
|
ids.flatten!
|
143
|
-
raise TextMagic::API::Error.new(4,
|
144
|
-
hash = Executor.execute(
|
143
|
+
raise TextMagic::API::Error.new(4, "Insufficient parameters") if ids.empty?
|
144
|
+
hash = Executor.execute("message_status", @username, @password, :ids => ids.join(","))
|
145
145
|
TextMagic::API::Response.message_status(hash, single)
|
146
146
|
end
|
147
147
|
alias :status :message_status
|
@@ -162,20 +162,20 @@ module TextMagic
|
|
162
162
|
# Example usage:
|
163
163
|
#
|
164
164
|
# replies = api.receive
|
165
|
-
# # => [
|
165
|
+
# # => ["999271828182: Hello Fred", "999314159265: Good day"]
|
166
166
|
# replies.first.text
|
167
|
-
# # =>
|
167
|
+
# # => "Hello Fred"
|
168
168
|
# replies.first.from
|
169
|
-
# # =>
|
169
|
+
# # => "999314159265"
|
170
170
|
# replies.last.message_id
|
171
|
-
# # =>
|
172
|
-
# api.receive
|
171
|
+
# # => "223606"
|
172
|
+
# api.receive "223606"
|
173
173
|
# # => []
|
174
174
|
#
|
175
175
|
# <b>It is strongly encouraged to setup callbacks to receive replies instead of
|
176
176
|
# using this method.</b>
|
177
177
|
def receive(last_retrieved_id = nil)
|
178
|
-
hash = Executor.execute(
|
178
|
+
hash = Executor.execute("receive", @username, @password, :last_retrieved_id => last_retrieved_id)
|
179
179
|
TextMagic::API::Response.receive(hash)
|
180
180
|
end
|
181
181
|
|
@@ -188,14 +188,14 @@ module TextMagic
|
|
188
188
|
#
|
189
189
|
# Example usage:
|
190
190
|
#
|
191
|
-
# api.delete_reply(
|
192
|
-
# api.delete_reply(
|
193
|
-
# api.delete_reply([
|
191
|
+
# api.delete_reply("141421")
|
192
|
+
# api.delete_reply("173205", "223606")
|
193
|
+
# api.delete_reply(["244948", "264575"])
|
194
194
|
def delete_reply(*ids)
|
195
195
|
single = ids.size == 1 && ids.first.is_a?(String)
|
196
196
|
ids.flatten!
|
197
|
-
raise TextMagic::API::Error.new(4,
|
198
|
-
Executor.execute(
|
197
|
+
raise TextMagic::API::Error.new(4, "Insufficient parameters") if ids.empty?
|
198
|
+
Executor.execute("delete_reply", @username, @password, :ids => ids.join(","))
|
199
199
|
true
|
200
200
|
end
|
201
201
|
alias :delete :delete_reply
|
@@ -212,34 +212,34 @@ module TextMagic
|
|
212
212
|
#
|
213
213
|
# Example usage:
|
214
214
|
#
|
215
|
-
# check = api.check_number(
|
215
|
+
# check = api.check_number("447624800500")
|
216
216
|
# check.price
|
217
217
|
# # => 0.8
|
218
218
|
# check.country
|
219
|
-
# # =>
|
219
|
+
# # => "GB"
|
220
220
|
#
|
221
221
|
# Example with multiple phone numbers:
|
222
222
|
#
|
223
|
-
# check = api.check_number(
|
224
|
-
# check[
|
223
|
+
# check = api.check_number("447624800500", "61428102137")
|
224
|
+
# check["447624800500"].price
|
225
225
|
# # => 0.8
|
226
|
-
# check[
|
227
|
-
# # =>
|
226
|
+
# check["61428102137"].country
|
227
|
+
# # => "AU"
|
228
228
|
#
|
229
229
|
# Multiple phone number can be supplied as an array or as a list of arguments:
|
230
230
|
#
|
231
|
-
# api.check_number([
|
232
|
-
# api.check_number(
|
231
|
+
# api.check_number(["447624800500", "61428102137"])
|
232
|
+
# api.check_number("447624800500", "61428102137")
|
233
233
|
#
|
234
234
|
# If you want to check a single phone number but still want to get
|
235
235
|
# a hash response, put the number in an array:
|
236
236
|
#
|
237
|
-
# api.check_number([
|
237
|
+
# api.check_number(["447624800500"])
|
238
238
|
def check_number(*phones)
|
239
239
|
single = phones.size == 1 && phones.first.is_a?(String)
|
240
240
|
phones.flatten!
|
241
|
-
raise TextMagic::API::Error.new(4,
|
242
|
-
hash = Executor.execute(
|
241
|
+
raise TextMagic::API::Error.new(4, "Insufficient parameters") if phones.empty?
|
242
|
+
hash = Executor.execute("check_number", @username, @password, :phone => phones.join(","))
|
243
243
|
TextMagic::API::Response.check_number(hash, single)
|
244
244
|
end
|
245
245
|
alias :check :check_number
|
data/lib/charset.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
module TextMagic
|
2
4
|
|
3
5
|
class API
|
@@ -21,7 +23,7 @@ module TextMagic
|
|
21
23
|
end
|
22
24
|
|
23
25
|
def real_length(text, unicode)
|
24
|
-
text.size + (unicode ? 0 : text.scan(/[\{\}
|
26
|
+
text.size + (unicode ? 0 : text.scan(/[\{\}\\~\[\]\|€]/).size)
|
25
27
|
end
|
26
28
|
end
|
27
29
|
end
|
data/lib/error.rb
CHANGED
@@ -10,10 +10,10 @@ module TextMagic
|
|
10
10
|
# can be supplied as arguments or in a hash.
|
11
11
|
#
|
12
12
|
# TextMagic::API::Error.new(code, message)
|
13
|
-
# TextMagic::API::Error.new(
|
13
|
+
# TextMagic::API::Error.new("error_code" => code, "error_message" => message)
|
14
14
|
def initialize(*args)
|
15
15
|
if args.first.is_a?(Hash)
|
16
|
-
@code, @message = args.first[
|
16
|
+
@code, @message = args.first["error_code"], args.first["error_message"]
|
17
17
|
else
|
18
18
|
@code, @message = args
|
19
19
|
end
|
data/lib/executor.rb
CHANGED
@@ -13,21 +13,21 @@ module TextMagic
|
|
13
13
|
# directly.
|
14
14
|
#
|
15
15
|
# Parameters specified in the +options+ hash will be added to the
|
16
|
-
# HTTP POST request
|
16
|
+
# HTTP POST request"s body together with command, username and
|
17
17
|
# password.
|
18
18
|
#
|
19
|
-
# Returns a hash with values parsed from the server
|
19
|
+
# Returns a hash with values parsed from the server"s response if
|
20
20
|
# the command was successfully executed. In case the server replies
|
21
21
|
# with error, this method raises a TextMagic::API::Error.
|
22
22
|
def self.execute(command, username, password, options = {})
|
23
|
-
raise TextMagic::API::Error.new(3,
|
23
|
+
raise TextMagic::API::Error.new(3, "Command is undefined") if command.nil? || command.blank?
|
24
24
|
if username.nil? || username.blank? || password.nil? || password.blank?
|
25
|
-
raise TextMagic::API::Error.new(5,
|
25
|
+
raise TextMagic::API::Error.new(5, "Invalid username & password combination")
|
26
26
|
end
|
27
27
|
options.merge!(:username => username, :password => password, :cmd => command)
|
28
28
|
options.delete_if { |key, value| key.nil? || key.to_s.blank? || value.nil? || value.to_s.blank? }
|
29
|
-
response = self.post(
|
30
|
-
raise Error.new(response) if response && response[
|
29
|
+
response = self.post("/api", :body => options, :format => :json)
|
30
|
+
raise Error.new(response) if response && response["error_code"]
|
31
31
|
response
|
32
32
|
end
|
33
33
|
end
|
data/lib/response.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "ostruct"
|
2
2
|
|
3
3
|
module TextMagic
|
4
4
|
|
@@ -16,49 +16,49 @@ module TextMagic
|
|
16
16
|
def self.send(hash, single)
|
17
17
|
response = nil
|
18
18
|
if single
|
19
|
-
response = hash[
|
19
|
+
response = hash["message_id"].keys.first.dup
|
20
20
|
else
|
21
|
-
response = hash[
|
21
|
+
response = hash["message_id"].invert
|
22
22
|
end
|
23
23
|
metaclass = class << response; self; end
|
24
24
|
metaclass.send :attr_accessor, :sent_text, :parts_count, :message_id
|
25
|
-
response.sent_text = hash[
|
26
|
-
response.parts_count = hash[
|
27
|
-
response.message_id = hash[
|
25
|
+
response.sent_text = hash["sent_text"]
|
26
|
+
response.parts_count = hash["parts_count"]
|
27
|
+
response.message_id = hash["message_id"]
|
28
28
|
response
|
29
29
|
end
|
30
30
|
|
31
31
|
def self.message_status(hash, single)
|
32
32
|
response = {}
|
33
33
|
hash.each do |message_id, message_hash|
|
34
|
-
status = message_hash[
|
34
|
+
status = message_hash["status"].dup
|
35
35
|
metaclass = class << status; self; end
|
36
36
|
metaclass.send :attr_accessor, :text, :credits_cost, :reply_number, :message_status, :created_time, :completed_time
|
37
|
-
status.text = message_hash[
|
38
|
-
status.credits_cost = message_hash[
|
39
|
-
status.reply_number = message_hash[
|
40
|
-
status.message_status = message_hash[
|
41
|
-
status.created_time = Time.at(message_hash[
|
42
|
-
status.completed_time = Time.at(message_hash[
|
37
|
+
status.text = message_hash["text"]
|
38
|
+
status.credits_cost = message_hash["credits_cost"]
|
39
|
+
status.reply_number = message_hash["reply_number"]
|
40
|
+
status.message_status = message_hash["message_status"]
|
41
|
+
status.created_time = Time.at(message_hash["created_time"].to_i) if message_hash["created_time"]
|
42
|
+
status.completed_time = Time.at(message_hash["completed_time"].to_i) if message_hash["completed_time"]
|
43
43
|
response[message_id] = status
|
44
44
|
end
|
45
45
|
single ? response.values.first : response
|
46
46
|
end
|
47
47
|
|
48
48
|
def self.receive(hash)
|
49
|
-
response = hash[
|
50
|
-
message = "#{message_hash[
|
49
|
+
response = hash["messages"].collect do |message_hash|
|
50
|
+
message = "#{message_hash["from"]}: #{message_hash["text"]}"
|
51
51
|
metaclass = class << message; self; end
|
52
52
|
metaclass.send :attr_accessor, :timestamp, :message_id, :text, :from
|
53
|
-
message.text = message_hash[
|
54
|
-
message.from = message_hash[
|
55
|
-
message.message_id = message_hash[
|
56
|
-
message.timestamp = Time.at(message_hash[
|
53
|
+
message.text = message_hash["text"]
|
54
|
+
message.from = message_hash["from"]
|
55
|
+
message.message_id = message_hash["message_id"]
|
56
|
+
message.timestamp = Time.at(message_hash["timestamp"].to_i)
|
57
57
|
message
|
58
58
|
end
|
59
59
|
metaclass = class << response; self; end
|
60
60
|
metaclass.send :attr_accessor, :unread
|
61
|
-
response.unread = hash[
|
61
|
+
response.unread = hash["unread"]
|
62
62
|
response
|
63
63
|
end
|
64
64
|
|