rfsms 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +29 -0
- data/bin/autospec +16 -0
- data/bin/htmldiff +16 -0
- data/bin/ldiff +16 -0
- data/bin/nokogiri +16 -0
- data/bin/rackup +16 -0
- data/bin/rake +16 -0
- data/bin/rspec +16 -0
- data/lib/rfsms.rb +307 -0
- data/spec/rfsms/answer_spec.rb +40 -0
- data/spec/rfsms/balance_answer_spec.rb +38 -0
- data/spec/rfsms/cancel_answer_spec.rb +52 -0
- data/spec/rfsms/connection_spec.rb +83 -0
- data/spec/rfsms/send_answer_spec.rb +95 -0
- data/spec/spec_helper.rb +5 -0
- metadata +93 -0
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#
|
2
|
+
# To change this template, choose Tools | Templates
|
3
|
+
# and open the template in the editor.
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'rake'
|
7
|
+
require 'rake/clean'
|
8
|
+
#require 'rake/rdoctask'
|
9
|
+
#require 'rdoc/task'
|
10
|
+
require 'rake/testtask'
|
11
|
+
require 'rspec/core/rake_task'
|
12
|
+
|
13
|
+
#Rake::RDocTask.new do |rdoc|
|
14
|
+
# files =['README', 'LICENSE', 'lib/**/*.rb']
|
15
|
+
# rdoc.rdoc_files.add(files)
|
16
|
+
# rdoc.main = "README" # page to start on
|
17
|
+
# rdoc.title = "Rfsms Docs"
|
18
|
+
# rdoc.rdoc_dir = 'doc/rdoc' # rdoc output folder
|
19
|
+
# rdoc.options << '--line-numbers'
|
20
|
+
#end
|
21
|
+
|
22
|
+
Rake::TestTask.new do |t|
|
23
|
+
t.test_files = FileList['test/**/*.rb']
|
24
|
+
end
|
25
|
+
|
26
|
+
RSpec::Core::RakeTask.new do |spec|
|
27
|
+
spec.pattern = 'spec/**/*.rb'
|
28
|
+
spec.rspec_opts = ['--backtrace']
|
29
|
+
end
|
data/bin/autospec
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This file was generated by Bundler.
|
4
|
+
#
|
5
|
+
# The application 'autospec' is installed as part of a gem, and
|
6
|
+
# this file is here to facilitate running it.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'pathname'
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
11
|
+
Pathname.new(__FILE__).realpath)
|
12
|
+
|
13
|
+
require 'rubygems'
|
14
|
+
require 'bundler/setup'
|
15
|
+
|
16
|
+
load Gem.bin_path('rspec-core', 'autospec')
|
data/bin/htmldiff
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This file was generated by Bundler.
|
4
|
+
#
|
5
|
+
# The application 'htmldiff' is installed as part of a gem, and
|
6
|
+
# this file is here to facilitate running it.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'pathname'
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
11
|
+
Pathname.new(__FILE__).realpath)
|
12
|
+
|
13
|
+
require 'rubygems'
|
14
|
+
require 'bundler/setup'
|
15
|
+
|
16
|
+
load Gem.bin_path('diff-lcs', 'htmldiff')
|
data/bin/ldiff
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This file was generated by Bundler.
|
4
|
+
#
|
5
|
+
# The application 'ldiff' is installed as part of a gem, and
|
6
|
+
# this file is here to facilitate running it.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'pathname'
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
11
|
+
Pathname.new(__FILE__).realpath)
|
12
|
+
|
13
|
+
require 'rubygems'
|
14
|
+
require 'bundler/setup'
|
15
|
+
|
16
|
+
load Gem.bin_path('diff-lcs', 'ldiff')
|
data/bin/nokogiri
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This file was generated by Bundler.
|
4
|
+
#
|
5
|
+
# The application 'nokogiri' is installed as part of a gem, and
|
6
|
+
# this file is here to facilitate running it.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'pathname'
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
11
|
+
Pathname.new(__FILE__).realpath)
|
12
|
+
|
13
|
+
require 'rubygems'
|
14
|
+
require 'bundler/setup'
|
15
|
+
|
16
|
+
load Gem.bin_path('nokogiri', 'nokogiri')
|
data/bin/rackup
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This file was generated by Bundler.
|
4
|
+
#
|
5
|
+
# The application 'rackup' is installed as part of a gem, and
|
6
|
+
# this file is here to facilitate running it.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'pathname'
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
11
|
+
Pathname.new(__FILE__).realpath)
|
12
|
+
|
13
|
+
require 'rubygems'
|
14
|
+
require 'bundler/setup'
|
15
|
+
|
16
|
+
load Gem.bin_path('rack', 'rackup')
|
data/bin/rake
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This file was generated by Bundler.
|
4
|
+
#
|
5
|
+
# The application 'rake' is installed as part of a gem, and
|
6
|
+
# this file is here to facilitate running it.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'pathname'
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
11
|
+
Pathname.new(__FILE__).realpath)
|
12
|
+
|
13
|
+
require 'rubygems'
|
14
|
+
require 'bundler/setup'
|
15
|
+
|
16
|
+
load Gem.bin_path('rake', 'rake')
|
data/bin/rspec
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This file was generated by Bundler.
|
4
|
+
#
|
5
|
+
# The application 'rspec' is installed as part of a gem, and
|
6
|
+
# this file is here to facilitate running it.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'pathname'
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
11
|
+
Pathname.new(__FILE__).realpath)
|
12
|
+
|
13
|
+
require 'rubygems'
|
14
|
+
require 'bundler/setup'
|
15
|
+
|
16
|
+
load Gem.bin_path('rspec-core', 'rspec')
|
data/lib/rfsms.rb
ADDED
@@ -0,0 +1,307 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
# Sender SMS via rfsms.ru
|
3
|
+
# v0.1.1
|
4
|
+
|
5
|
+
require 'net/http'
|
6
|
+
require 'net/https'
|
7
|
+
require 'nori'
|
8
|
+
require 'i18n'
|
9
|
+
require 'active_support/all'
|
10
|
+
|
11
|
+
Nori.configure do |config|
|
12
|
+
config.convert_tags_to { |tag| tag.to_s.underscore.to_sym }
|
13
|
+
end
|
14
|
+
|
15
|
+
module Rfsms
|
16
|
+
DATEREGEXP = /^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[1-2]\d|3[01]) (?:[01]\d|2[0-4]):(?:[0-5]\d):(?:[0-5]\d)$/
|
17
|
+
DATEFORMAT = "%Y-%m-%d %H:%M:%S"
|
18
|
+
INTEGER_REGEXP = /^\d+$/
|
19
|
+
FLOAT_REGEXP = /^\d+(?:\.\d+)?$/
|
20
|
+
|
21
|
+
class AnswerError < RuntimeError; end
|
22
|
+
class IncorrectAnswerError < AnswerError; end
|
23
|
+
|
24
|
+
class Answer
|
25
|
+
attr_reader :descr
|
26
|
+
|
27
|
+
# Инициализация объекта ответа с проверкой элементов в передаваемом блоке validate.
|
28
|
+
# Если validate возвращает false или nil возникает исключение Rfsms::IncorrectAnswerError
|
29
|
+
def initialize(body, &validate)
|
30
|
+
body_e = Nori.parse(body, :nokogiri)
|
31
|
+
p body_e if $DEBUG
|
32
|
+
|
33
|
+
elements = body_e[:data]
|
34
|
+
raise IncorrectAnswerError unless elements.is_a?(Hash)
|
35
|
+
p elements if $DEBUG
|
36
|
+
|
37
|
+
if code = elements.delete(:code) and @descr = elements.delete(:descr)
|
38
|
+
if code == '1'
|
39
|
+
raise IncorrectAnswerError if validate and !validate.call(elements)
|
40
|
+
elements.each_pair do |tag, value|
|
41
|
+
instance_variable_set(:"@#{tag}", value)
|
42
|
+
end
|
43
|
+
else
|
44
|
+
raise AnswerError, "#{code}: #{@descr}"
|
45
|
+
end
|
46
|
+
else
|
47
|
+
raise IncorrectAnswerError
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class CancelAnswer < Answer
|
53
|
+
attr_reader :action, :cancel_col
|
54
|
+
|
55
|
+
def initialize(body)
|
56
|
+
super(body) do |e|
|
57
|
+
e[:action] =~ /^(?:check|make)$/
|
58
|
+
end
|
59
|
+
@cancel_col = @cancel_col.to_i
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class SendAnswer < Answer
|
64
|
+
attr_reader :smsid, :datetime, :action, :all_recivers,
|
65
|
+
:col_send_abonent, :col_non_send_abonent, :price_of_sending,
|
66
|
+
:colsms_of_sending, :price
|
67
|
+
|
68
|
+
def initialize(body)
|
69
|
+
super(body) do |e|
|
70
|
+
e.has_key?(:smsid) and
|
71
|
+
e[:datetime] =~ DATEREGEXP and
|
72
|
+
e[:action] =~ /^(?:check|make|send)$/ and
|
73
|
+
e[:all_recivers] =~ INTEGER_REGEXP and
|
74
|
+
e[:col_send_abonent] =~ INTEGER_REGEXP and
|
75
|
+
e[:col_non_send_abonent] =~ INTEGER_REGEXP and
|
76
|
+
e[:price_of_sending] =~ FLOAT_REGEXP and
|
77
|
+
e[:colsms_of_sending] =~ INTEGER_REGEXP and
|
78
|
+
e[:price] =~ FLOAT_REGEXP
|
79
|
+
end
|
80
|
+
@datetime = DateTime.strptime(@datetime, DATEFORMAT)
|
81
|
+
@all_recivers = @all_recivers.to_i
|
82
|
+
@col_send_abonent = @col_send_abonent.to_i
|
83
|
+
@col_non_send_abonent = @col_non_send_abonent.to_i
|
84
|
+
@price_of_sending = @price_of_sending.to_f
|
85
|
+
@colsms_of_sending = @colsms_of_sending.to_i
|
86
|
+
@price = @price.to_f
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class BalanceAnswer < Answer
|
91
|
+
attr_reader :account
|
92
|
+
|
93
|
+
def to_f
|
94
|
+
self.account
|
95
|
+
end
|
96
|
+
|
97
|
+
def to_s
|
98
|
+
self.to_f.to_s
|
99
|
+
end
|
100
|
+
|
101
|
+
def to_str
|
102
|
+
self.to_s
|
103
|
+
end
|
104
|
+
|
105
|
+
def +(other)
|
106
|
+
case other
|
107
|
+
when Float
|
108
|
+
self.to_f + other
|
109
|
+
when Integer, BalanceAnswer
|
110
|
+
self.to_f + other.to_f
|
111
|
+
else
|
112
|
+
n1, n2 = other.coerce(self)
|
113
|
+
n1 + n2
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def coerce(other)
|
118
|
+
case other
|
119
|
+
when Float
|
120
|
+
return other, self.to_f
|
121
|
+
when Integer
|
122
|
+
return other.to_f, self
|
123
|
+
when String
|
124
|
+
return other, self.to_s
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def initialize(body)
|
129
|
+
super(body) do |e|
|
130
|
+
e[:account] =~ FLOAT_REGEXP
|
131
|
+
end
|
132
|
+
@account = @account.to_f
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
class ReportAnswer < Answer
|
137
|
+
attr_reader :sms
|
138
|
+
class SMS
|
139
|
+
attr_reader :smsid, :datetime, :text, :source, :all_col, :delivered_col,
|
140
|
+
:not_delivered_col, :waiting_col, :enqueued_col, :payment
|
141
|
+
|
142
|
+
def initialize(elements)
|
143
|
+
p elements if $DEBUG
|
144
|
+
unless @smsid = elements[:smsid] and
|
145
|
+
@datetime = elements[:datetime] and @datetime =~ DATEREGEXP and
|
146
|
+
@text = elements[:text] and
|
147
|
+
@source = elements[:source] and
|
148
|
+
@all_col = elements[:all_col] and
|
149
|
+
@delivered_col = elements[:delivered_col] and
|
150
|
+
@not_delivered_col = elements[:not_delivered_col] and
|
151
|
+
@waiting_col = elements[:waiting_col] and
|
152
|
+
@enqueued_col = elements[:enqueued_col] and
|
153
|
+
@payment = elements[:payment]
|
154
|
+
raise IncorrectAnswerError
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def initialize(body)
|
160
|
+
super(body)
|
161
|
+
@sms = case @sms
|
162
|
+
when Hash
|
163
|
+
[SMS.new(@sms)]
|
164
|
+
when Array
|
165
|
+
@sms.map {|sms| SMS.new(sms) }
|
166
|
+
else
|
167
|
+
[]
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
class Connection
|
173
|
+
def initialize(url, login, password)
|
174
|
+
@uri = URI.parse(url)
|
175
|
+
@connection = Net::HTTP.new(@uri.host, @uri.port)
|
176
|
+
@connection.use_ssl = true
|
177
|
+
@connection.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
178
|
+
@login = login
|
179
|
+
@password = password
|
180
|
+
end
|
181
|
+
|
182
|
+
# отправляет text по указанным phones = [].
|
183
|
+
#
|
184
|
+
# @param [String] text текст сообщения
|
185
|
+
# @param [Array<String, Hash>] phones телефоны на которые будет отправлено, может быть хэшем где значения - индивидуальный текст
|
186
|
+
# @param [Time] datetime время в которое необходимо отправить, nil - сейчас
|
187
|
+
# @param [String] source кто отправил
|
188
|
+
# @param [Boolean] onlydelivery)
|
189
|
+
# @return [Rfsms::SendAnswer]
|
190
|
+
def send(text, phones, datetime = nil, source = nil, onlydelivery = false)
|
191
|
+
message = message_header
|
192
|
+
message << "<text>#{text}</text>"
|
193
|
+
|
194
|
+
case phones
|
195
|
+
when Array
|
196
|
+
phones.each do |phone|
|
197
|
+
message << " <to number='#{phone}'></to>\n"
|
198
|
+
end
|
199
|
+
when Hash
|
200
|
+
phones.each_pair do |phone, t|
|
201
|
+
message << " <to number='#{phone}'>#{t}</to>\n"
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
message << "<datetime>#{datetime.strftime(DATEFORMAT)}</datetime>" if datetime
|
206
|
+
message << "<source>#{source}</source>" if source
|
207
|
+
message << "<onlydelivery>1</onlydelivery>" if onlydelivery
|
208
|
+
message << message_footer
|
209
|
+
|
210
|
+
STDERR.puts "+SENDED:\n"+message+"\n-SENDED\n" if $DEBUG
|
211
|
+
@connection.request_post('/send.xml', message) do |response|
|
212
|
+
case response
|
213
|
+
when Net::HTTPSuccess
|
214
|
+
return SendAnswer.new(response.body)
|
215
|
+
else
|
216
|
+
response.error!
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# получает отчет о списке рассылки при указанных датах начала(start) и
|
222
|
+
# конца(stop) типа Time
|
223
|
+
# если даты не указаны получает за весь период
|
224
|
+
#
|
225
|
+
# @param [Hash{Symbol => Time}] options :start - начало, :stop - окончание
|
226
|
+
# @return [Rfsms::ReportAnswer]
|
227
|
+
def report(options = {})
|
228
|
+
message = message_header
|
229
|
+
unless options.empty?
|
230
|
+
start, stop = options[:start].strftime(DATEFORMAT), options[:stop].strftime(DATEFORMAT)
|
231
|
+
if start =~ DATEREGEXP and stop =~ DATEREGEXP
|
232
|
+
message << <<-PERIOD
|
233
|
+
<start>#{start}</start>
|
234
|
+
<stop>#{stop}</stop>
|
235
|
+
PERIOD
|
236
|
+
else
|
237
|
+
raise ArgumentError, "Date #{start} or date #{stop} is incorrect!"
|
238
|
+
end
|
239
|
+
end
|
240
|
+
message << message_footer
|
241
|
+
|
242
|
+
STDERR.puts "+SENDED:\n"+message+"\n-SENDED\n" if $DEBUG
|
243
|
+
@connection.request_post('/report.xml', message) do |response|
|
244
|
+
case response
|
245
|
+
when Net::HTTPSuccess
|
246
|
+
return ReportAnswer.new(response.body)
|
247
|
+
else
|
248
|
+
response.error!
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
# возвращает текущий баланс
|
254
|
+
#
|
255
|
+
# @return [Rfsms::BalanceAnwer]
|
256
|
+
def balance
|
257
|
+
message = message_header + message_footer
|
258
|
+
STDERR.puts "+SENDED:\n"+message+"\n-SENDED\n" if $DEBUG
|
259
|
+
@connection.request_post('/balance.xml', message) do |response|
|
260
|
+
case response
|
261
|
+
when Net::HTTPSuccess
|
262
|
+
return BalanceAnswer.new(response.body)
|
263
|
+
else
|
264
|
+
response.error!
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
# отменяет СМС с идентификатором smsid
|
270
|
+
#
|
271
|
+
# @param [Integer, String] smsid
|
272
|
+
# @return [Rfsms::CancelAnswer]
|
273
|
+
def cancel(smsid)
|
274
|
+
message = message_header
|
275
|
+
message << <<END
|
276
|
+
<smsid>#{smsid}</smsid>
|
277
|
+
END
|
278
|
+
message << message_footer
|
279
|
+
STDERR.puts "+SENDED:\n"+message+"\n-SENDED\n" if $DEBUG
|
280
|
+
@connection.request_post('/cancel.xml', message) do |response|
|
281
|
+
case response
|
282
|
+
when Net::HTTPSuccess
|
283
|
+
return CancelAnswer.new(response.body)
|
284
|
+
else
|
285
|
+
response.error!
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
private
|
291
|
+
|
292
|
+
# формирует заголовок с данными авторизации
|
293
|
+
def message_header
|
294
|
+
<<END
|
295
|
+
<data>
|
296
|
+
<login>#{@login}</login>
|
297
|
+
<password>#{@password}</password>
|
298
|
+
END
|
299
|
+
end
|
300
|
+
|
301
|
+
# формирует подвал запроса
|
302
|
+
def message_footer
|
303
|
+
"</data>"
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Rfsms::Answer do
|
5
|
+
before(:each) do
|
6
|
+
@correct_body = <<-ANSWER
|
7
|
+
<data>
|
8
|
+
<code>1</code>
|
9
|
+
<descr>Операция успешно завершена</descr>
|
10
|
+
</data>
|
11
|
+
ANSWER
|
12
|
+
@correct_elements = Nori.parse(@correct_body, :nokogiri)[:data]
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "конструктор" do
|
16
|
+
it "при корректных входных данных должен создавать экземпляр с соответствующими входу полями" do
|
17
|
+
answer = Rfsms::Answer.new(@correct_body)
|
18
|
+
answer.should be_an_instance_of(Rfsms::Answer)
|
19
|
+
answer.descr.should be == @correct_elements[:descr]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "при значении элемента code отличного от 1 должен вызывать исключение Rfsms::AnswerError" do
|
23
|
+
lambda do
|
24
|
+
Rfsms::Answer.new(@correct_body.gsub(%r{(?<=<code>)\d+(?=</code>)}, '500'))
|
25
|
+
end.should raise_error Rfsms::AnswerError
|
26
|
+
end
|
27
|
+
|
28
|
+
it "при отсутствии одного из входных элементов вызывает исключение Rfsms::IncorrectAnswerError" do
|
29
|
+
lambda do
|
30
|
+
incorrect_elements = @correct_body.gsub(%r{<code>.*</code>}, '')
|
31
|
+
Rfsms::Answer.new(incorrect_elements)
|
32
|
+
end.should raise_error(Rfsms::IncorrectAnswerError)
|
33
|
+
lambda do
|
34
|
+
incorrect_elements = @correct_body.gsub(%r{<descr>.*</descr>}, '')
|
35
|
+
Rfsms::Answer.new(incorrect_elements)
|
36
|
+
end.should raise_error(Rfsms::IncorrectAnswerError)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Rfsms::BalanceAnswer do
|
5
|
+
before(:each) do
|
6
|
+
@correct_body = <<-ANSWER
|
7
|
+
<data>
|
8
|
+
<code>1</code>
|
9
|
+
<descr>Операция успешно завершена</descr>
|
10
|
+
<account>10000.94</account>
|
11
|
+
</data>
|
12
|
+
ANSWER
|
13
|
+
@correct_elements = Nori.parse(@correct_body, :nokogiri)[:data]
|
14
|
+
end
|
15
|
+
|
16
|
+
it "при корректных входных данных конструктор создает объект с соответствующими входу полями" do
|
17
|
+
correct_balance_answer = Rfsms::BalanceAnswer.new(@correct_body)
|
18
|
+
correct_balance_answer.should be_an_instance_of(Rfsms::BalanceAnswer)
|
19
|
+
correct_balance_answer.descr.should be == @correct_elements[:descr]
|
20
|
+
correct_balance_answer.account.should be == @correct_elements[:account].to_f
|
21
|
+
end
|
22
|
+
|
23
|
+
it "при отсутствии одного из входных элементов конструктор вызывает исключение Rfsms::IncorrectAnswerError" do
|
24
|
+
lambda do
|
25
|
+
incorrect_elements = @correct_body.gsub(%r{<code>.*</code>}, '')
|
26
|
+
Rfsms::BalanceAnswer.new(incorrect_elements)
|
27
|
+
end.should raise_error(Rfsms::IncorrectAnswerError)
|
28
|
+
lambda do
|
29
|
+
incorrect_elements = @correct_body.gsub(%r{<descr>.*</descr>}, '')
|
30
|
+
Rfsms::BalanceAnswer.new(incorrect_elements)
|
31
|
+
end.should raise_error(Rfsms::IncorrectAnswerError)
|
32
|
+
lambda do
|
33
|
+
incorrect_elements = @correct_body.gsub(%r{<account>.*</account>}, '')
|
34
|
+
Rfsms::BalanceAnswer.new(incorrect_elements)
|
35
|
+
end.should raise_error(Rfsms::IncorrectAnswerError)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Rfsms::CancelAnswer do
|
5
|
+
before(:each) do
|
6
|
+
@correct_body = <<-ANSWER
|
7
|
+
<data>
|
8
|
+
<code>1</code>
|
9
|
+
<descr>Операция завершена успешно</descr>
|
10
|
+
<action>make</action>
|
11
|
+
</data>
|
12
|
+
ANSWER
|
13
|
+
@correct_elements = Nori.parse(@correct_body, :nokogiri)[:data]
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "конструктор" do
|
17
|
+
it "при корректных входных данных создает экземпляр ответа с соответствующими входу полями" do
|
18
|
+
cancel_answer = Rfsms::CancelAnswer.new(@correct_body)
|
19
|
+
cancel_answer.should be_an_instance_of(Rfsms::CancelAnswer)
|
20
|
+
cancel_answer.descr.should be == @correct_elements[:descr]
|
21
|
+
cancel_answer.action.should be == @correct_elements[:action]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "при отсутствии одного из входных элементов вызывает исключение Rfsms::IncorrectAnswerError" do
|
25
|
+
lambda do
|
26
|
+
incorrect_elements = @correct_body.gsub(%r{<code>\d+</code>}, '')
|
27
|
+
Rfsms::CancelAnswer.new(incorrect_elements)
|
28
|
+
end.should raise_error(Rfsms::IncorrectAnswerError)
|
29
|
+
lambda do
|
30
|
+
incorrect_elements = @correct_body.gsub(%r{<descr>.+</descr>}, '')
|
31
|
+
Rfsms::CancelAnswer.new(incorrect_elements)
|
32
|
+
end.should raise_error(Rfsms::IncorrectAnswerError)
|
33
|
+
lambda do
|
34
|
+
incorrect_elements = @correct_body.gsub(%r{<action>.+</action>}, '')
|
35
|
+
Rfsms::CancelAnswer.new(incorrect_elements)
|
36
|
+
end.should raise_error(Rfsms::IncorrectAnswerError)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "при значении входного элемента action отличного от make или check вызывает исключение Rfsms::IncorrectAnswerError" do
|
40
|
+
lambda do
|
41
|
+
Rfsms::CancelAnswer.new(@correct_body.gsub(%r{(?<=<action>).+(?=</action>)}, 'make'))
|
42
|
+
end.should_not raise_error(Rfsms::IncorrectAnswerError)
|
43
|
+
lambda do
|
44
|
+
Rfsms::CancelAnswer.new(@correct_body.gsub(%r{(?<=<action>).+(?=</action>)}, 'check'))
|
45
|
+
end.should_not raise_error(Rfsms::IncorrectAnswerError)
|
46
|
+
lambda do
|
47
|
+
Rfsms::CancelAnswer.new(@correct_body.gsub(%r{(?<=<action>).+(?=</action>)}, 'incorrect'))
|
48
|
+
end.should raise_error(Rfsms::IncorrectAnswerError)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Rfsms::Connection do
|
5
|
+
before(:all) do
|
6
|
+
@connection = Rfsms::Connection.new('https://transport.rfsms.ru:7214', 'newcom', 'newc0w2m2')
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "Метод send(message, phones)" do
|
10
|
+
it "при отправке SMS по списку правильных номеров должен возвращать ответ (Rfsms::Answer)" do
|
11
|
+
correct_phones = [PHONE, '8-909-190-9409']
|
12
|
+
send_answer = nil
|
13
|
+
lambda { send_answer = @connection.send('test', correct_phones) }.should_not raise_error
|
14
|
+
send_answer.should be_an_instance_of(Rfsms::SendAnswer)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "должен вызывать исключение AnswerError, если все номера некорректны" do
|
18
|
+
incorrect_phones = ['8912383887', '8-909-190-94097']
|
19
|
+
lambda { @connection.send('test', incorrect_phones) }.should raise_error Rfsms::AnswerError
|
20
|
+
end
|
21
|
+
|
22
|
+
it "должен возвращать количество отправленных SMS соответствующее количеству корректных номеров" do
|
23
|
+
correct_phones = [PHONE, '8-909-190-9409']
|
24
|
+
incorrect_phones = ['8912383887', '8-909-190-94097']
|
25
|
+
answer = nil
|
26
|
+
lambda { answer = @connection.send('test', incorrect_phones.concat(correct_phones)) }.should_not raise_error
|
27
|
+
answer.col_send_abonent.should be == 2
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "Метод report(start, stop)" do
|
32
|
+
it "должен получать список рассылки за определенный период при корректно указанных датах начала и конца" do
|
33
|
+
start = Time.now - 2.hour
|
34
|
+
correct_phones = [PHONE]
|
35
|
+
@connection.send('test', correct_phones).should be_an_instance_of(Rfsms::SendAnswer)
|
36
|
+
stop = Time.now + 2.hour
|
37
|
+
|
38
|
+
report = @connection.report(:start => start, :stop => stop)
|
39
|
+
report.should be_an_instance_of(Rfsms::ReportAnswer)
|
40
|
+
report.sms.size.should be > 0
|
41
|
+
end
|
42
|
+
|
43
|
+
it "должен получать список рассылки за весь период при неуказанных дате начала и конца" do
|
44
|
+
# TODO: Исключить это дублирование
|
45
|
+
# start = Time.now
|
46
|
+
# correct_phones = ['89123838878']
|
47
|
+
# @connection.send('test', correct_phones)
|
48
|
+
# stop = Time.now
|
49
|
+
#
|
50
|
+
# @connection.send('test2', correct_phones)
|
51
|
+
#
|
52
|
+
# report_with_period = @connection.report(:start => start, :stop => stop)
|
53
|
+
# report_with_period.should be_an_instance_of(Rfsms::ReportAnswer)
|
54
|
+
#
|
55
|
+
# report = @connection.report
|
56
|
+
# report.should be_an_instance_of(Rfsms::ReportAnswer)
|
57
|
+
#
|
58
|
+
# report.sms.size.should be > report_with_period.sms.size
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "Метод balance()" do
|
63
|
+
it "должен возвращать текущее значение баланса типа Float в поле account созданного объекта" do
|
64
|
+
balance = nil
|
65
|
+
lambda { balance = @connection.balance }.should_not raise_error
|
66
|
+
balance.should be_an_instance_of(Rfsms::BalanceAnswer)
|
67
|
+
balance.account.should be_an_instance_of(Float)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "Метод cancel(smsid)" do
|
72
|
+
it "должен отменять отложенную SMS (группу SMS) с идентификатором smsid и возвращать Rfsms::CancelAnswer" do
|
73
|
+
send_answer = @connection.send(
|
74
|
+
"Проверка отмены рассылки",
|
75
|
+
[PHONE],
|
76
|
+
Time.now + 1.hour
|
77
|
+
)
|
78
|
+
canceled = @connection.cancel(send_answer.smsid)
|
79
|
+
canceled.should be_an_instance_of(Rfsms::CancelAnswer)
|
80
|
+
canceled.cancel_col.should be > 0
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Rfsms::SendAnswer do
|
5
|
+
before(:each) do
|
6
|
+
# Элементы ответа от сервера при отправке 2 правильных sms
|
7
|
+
@correct_answer_body_for_2sms = <<-ANSWER
|
8
|
+
<data>
|
9
|
+
<code>1</code>
|
10
|
+
<descr>Операция успешно завершена</descr>
|
11
|
+
<smsid>un1quine221d</smsid>
|
12
|
+
<datetime>#{Time.now.strftime(DATETIME_FORMAT)}</datetime>
|
13
|
+
<action>send</action>
|
14
|
+
<allRecivers>2</allRecivers>
|
15
|
+
<colSendAbonent>2</colSendAbonent>
|
16
|
+
<colNonSendAbonent>0</colNonSendAbonent>
|
17
|
+
<priceOfSending>0.76</priceOfSending>
|
18
|
+
<colsmsOfSending>2</colsmsOfSending>
|
19
|
+
<price>0.38</price>
|
20
|
+
</data>
|
21
|
+
ANSWER
|
22
|
+
@correct_answer_elements_for_2sms = Nori.parse(@correct_answer_body_for_2sms, :nokogiri)[:data]
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "конструктор" do
|
26
|
+
it "при корректных входных данных должен создавать экземпляр с соответствующими входу полями" do
|
27
|
+
send_answer = Rfsms::SendAnswer.new(@correct_answer_body_for_2sms)
|
28
|
+
send_answer.should be_an_instance_of(Rfsms::SendAnswer)
|
29
|
+
send_answer.descr.should be == @correct_answer_elements_for_2sms[:descr]
|
30
|
+
send_answer.smsid.should be == @correct_answer_elements_for_2sms[:smsid]
|
31
|
+
send_answer.datetime.should be == DateTime.strptime(@correct_answer_elements_for_2sms[:datetime], DATETIME_FORMAT)
|
32
|
+
send_answer.action.should be == @correct_answer_elements_for_2sms[:action]
|
33
|
+
send_answer.all_recivers.should be == @correct_answer_elements_for_2sms[:all_recivers].to_i
|
34
|
+
send_answer.col_send_abonent.should be == @correct_answer_elements_for_2sms[:col_send_abonent].to_i
|
35
|
+
send_answer.col_non_send_abonent.should be == @correct_answer_elements_for_2sms[:col_non_send_abonent].to_i
|
36
|
+
send_answer.price_of_sending.should be == @correct_answer_elements_for_2sms[:price_of_sending].to_f
|
37
|
+
send_answer.colsms_of_sending.should be == @correct_answer_elements_for_2sms[:colsms_of_sending].to_i
|
38
|
+
send_answer.price.should be == @correct_answer_elements_for_2sms[:price].to_f
|
39
|
+
end
|
40
|
+
|
41
|
+
it "при значении элемента code отличного от 1 должен вызывать исключение Rfsms::AnswerError" do
|
42
|
+
lambda do
|
43
|
+
Rfsms::SendAnswer.new(@correct_answer_body_for_2sms.gsub(%r{(?<=<code>).*(?=</code>)}, '500'))
|
44
|
+
end.should raise_error Rfsms::AnswerError
|
45
|
+
end
|
46
|
+
|
47
|
+
it "при отсутствии любого из входных данных должен вызывать исключение Rfsms::IncorrectAnswerError" do
|
48
|
+
lambda do
|
49
|
+
incorrect_elements = @correct_answer_body_for_2sms.gsub(%r{<code>.*</code>}, '')
|
50
|
+
Rfsms::SendAnswer.new(incorrect_elements)
|
51
|
+
end.should raise_error(Rfsms::IncorrectAnswerError)
|
52
|
+
lambda do
|
53
|
+
incorrect_elements = @correct_answer_body_for_2sms.gsub(%r{<descr>.*</descr>}, '')
|
54
|
+
Rfsms::SendAnswer.new(incorrect_elements)
|
55
|
+
end.should raise_error Rfsms::IncorrectAnswerError
|
56
|
+
lambda do
|
57
|
+
incorrect_elements = @correct_answer_body_for_2sms.gsub(%r{<smsid>.*</smsid>}, '')
|
58
|
+
Rfsms::SendAnswer.new(incorrect_elements)
|
59
|
+
end.should raise_error Rfsms::IncorrectAnswerError
|
60
|
+
lambda do
|
61
|
+
incorrect_elements = @correct_answer_body_for_2sms.gsub(%r{<datetime>.*</datetime>}, '')
|
62
|
+
Rfsms::SendAnswer.new(incorrect_elements)
|
63
|
+
end.should raise_error Rfsms::IncorrectAnswerError
|
64
|
+
lambda do
|
65
|
+
incorrect_elements = @correct_answer_body_for_2sms.gsub(%r{<action>.*</action>}, '')
|
66
|
+
Rfsms::SendAnswer.new(incorrect_elements)
|
67
|
+
end.should raise_error Rfsms::IncorrectAnswerError
|
68
|
+
lambda do
|
69
|
+
incorrect_elements = @correct_answer_body_for_2sms.gsub(%r{<allRecivers>.*</allRecivers>}, '')
|
70
|
+
Rfsms::SendAnswer.new(incorrect_elements)
|
71
|
+
end.should raise_error Rfsms::IncorrectAnswerError
|
72
|
+
lambda do
|
73
|
+
incorrect_elements = @correct_answer_body_for_2sms.gsub(%r{<colSendAbonent>.*</colSendAbonent>}, '')
|
74
|
+
Rfsms::SendAnswer.new(incorrect_elements)
|
75
|
+
end.should raise_error Rfsms::IncorrectAnswerError
|
76
|
+
lambda do
|
77
|
+
incorrect_elements = @correct_answer_body_for_2sms.gsub(%r{<colNonSendAbonent>.*</colNonSendAbonent>}, '')
|
78
|
+
Rfsms::SendAnswer.new(incorrect_elements)
|
79
|
+
end.should raise_error Rfsms::IncorrectAnswerError
|
80
|
+
lambda do
|
81
|
+
incorrect_elements = @correct_answer_body_for_2sms.gsub(%r{<priceOfSending>.*</priceOfSending>}, '')
|
82
|
+
Rfsms::SendAnswer.new(incorrect_elements)
|
83
|
+
end.should raise_error Rfsms::IncorrectAnswerError
|
84
|
+
lambda do
|
85
|
+
incorrect_elements = @correct_answer_body_for_2sms.gsub(%r{<colsmsOfSending>.*</colsmsOfSending>}, '')
|
86
|
+
Rfsms::SendAnswer.new(incorrect_elements)
|
87
|
+
end.should raise_error Rfsms::IncorrectAnswerError
|
88
|
+
lambda do
|
89
|
+
incorrect_elements = @correct_answer_body_for_2sms.gsub(%r{<price>.*</price>}, '')
|
90
|
+
Rfsms::SendAnswer.new(incorrect_elements)
|
91
|
+
end.should raise_error Rfsms::IncorrectAnswerError
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rfsms
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Danil Korotaev
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-01-11 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: nokogiri
|
16
|
+
requirement: &14005300 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.5.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *14005300
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: nori
|
27
|
+
requirement: &14001060 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.0.2
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *14001060
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: activesupport
|
38
|
+
requirement: &14013340 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 3.1.1
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *14013340
|
47
|
+
description: Sender SMS via rfsms.ru
|
48
|
+
email: greyd@mail333.com
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- Rakefile
|
54
|
+
- bin/rspec
|
55
|
+
- bin/rackup
|
56
|
+
- bin/autospec
|
57
|
+
- bin/rake
|
58
|
+
- bin/ldiff
|
59
|
+
- bin/htmldiff
|
60
|
+
- bin/nokogiri
|
61
|
+
- lib/rfsms.rb
|
62
|
+
- spec/rfsms/answer_spec.rb
|
63
|
+
- spec/rfsms/cancel_answer_spec.rb
|
64
|
+
- spec/rfsms/send_answer_spec.rb
|
65
|
+
- spec/rfsms/balance_answer_spec.rb
|
66
|
+
- spec/rfsms/connection_spec.rb
|
67
|
+
- spec/spec_helper.rb
|
68
|
+
homepage: http://rubygems.org/gems/rfsms
|
69
|
+
licenses: []
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options: []
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
requirements: []
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 1.8.15
|
89
|
+
signing_key:
|
90
|
+
specification_version: 3
|
91
|
+
summary: rfsms is sender SMS via rfsms.ru
|
92
|
+
test_files: []
|
93
|
+
has_rdoc:
|