mblox 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MmIxY2E0ZmM4NmU1ZWMwZmYwNGFmMDMyZGJkNDY4ZmQ2ZjhmNTM4Mw==
5
+ data.tar.gz: !binary |-
6
+ ZTExZGY3ODg3Mzg2M2RkNmQwMTUxNzI5YzRmMGMzYzc3ZjA1NzhlZg==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MGQ2MjM0YjY0MDk0MWU1MmIzNTRlZDQwZGIyZjhiNGQ2ZDQ3YjI1ODJmMjk1
10
+ YmVlZWViMGIxMjNhY2U1OGI4OGY3YzNlNWM4MGRkNTNjNDdjMzI0NjcxMDZi
11
+ YjMwY2MxMjk2ZjU1OThkMjM5MWQ2ZTBhNjQ1NTllZjE2MjJmNDg=
12
+ data.tar.gz: !binary |-
13
+ OTI0ZGM4YTlhNzZmMGU4ZTVkNjg0MjQ5NmUzZTBiZjNlNzBkNDY2Mjg4N2Y1
14
+ ZDQyNDUzMjMwMzk0MjI3YTIxM2UzN2FiYWM4YzkxMTg0ZGM2ZTQ0NzE1ZWI3
15
+ NmIwMjRjMzk4MmY4NTRiZmIyZjMxYTY3MzE1Y2FjODA1YTY4YmQ=
data/README.md CHANGED
@@ -29,7 +29,7 @@ Configuration
29
29
  config.partner_name = ...
30
30
  config.tariff = ...
31
31
  config.service_id = ...
32
-
32
+
33
33
  # You can also configure some logging options
34
34
  # In a Rails environment, config.logger will default to Rails.logger and config.log_at will default to :debug
35
35
  # config.log_at means the level at which Mblox will log.
@@ -38,7 +38,7 @@ Configuration
38
38
  # logging will be suppressed because it is below the log level of the logger.
39
39
  config.logger = Logger.new(STDOUT)
40
40
  config.log_at :info
41
-
41
+
42
42
  # What to do if messages are longer than 160 characters. Default is :raise_error
43
43
  # Other options are :truncate and :split
44
44
  config.on_message_too_long = :truncate
data/lib/mblox.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  require "mblox/configuration"
2
2
  require "mblox/sms"
3
- require "mblox/sms_error"
4
3
  require "mblox/version"
5
4
 
6
5
  module Mblox
data/lib/mblox/sms.rb CHANGED
@@ -1,26 +1,33 @@
1
+ # encoding: UTF-8
1
2
  require 'active_support/core_ext/hash'
2
3
  require 'addressable/uri'
3
4
  require 'builder'
4
5
  require "net/https"
6
+ require 'mblox/sms_response'
5
7
 
6
8
  module Mblox
7
9
  class Sms
10
+ class InvalidPhoneNumberError < ::ArgumentError; end
11
+ class InvalidMessageError < ::ArgumentError; end
8
12
  MAX_LENGTH = 160
9
13
  MAX_SECTION_LENGTH = MAX_LENGTH - "(MSG XXX/XXX): ".size
14
+ ILLEGAL_CHARACTERS = /([^a-zA-Z0-9!"#$\%&'\(\)*+,-.\/:;<=>?@_£¤¥§¿i¡ÄÅÆÇÉÑÖØÜßáäåæèéìñòöøùü\n\r\tí ])/
10
15
 
11
16
  attr_reader :phone, :message
12
17
 
13
18
  ON_MESSAGE_TOO_LONG_HANDLER = {
14
- :raise_error => Proc.new { raise SmsError, "Message cannot be longer than #{MAX_LENGTH} characters" },
19
+ :raise_error => Proc.new { raise InvalidMessageError, "Message cannot be longer than #{MAX_LENGTH} characters" },
15
20
  :truncate => Proc.new { |message| Mblox.log "Truncating message due to length. Message was: \"#{message}\" but will now be \"#{message = message[0,MAX_LENGTH]}\""; [message] },
16
21
  :split => Proc.new { |message| split_message(message) }
17
22
  }
18
23
 
19
24
  def initialize(phone,message)
20
25
  phone = phone.to_s
21
- raise SmsError, "Phone number must be ten digits" unless /\A[0-9]{10}\z/.match(phone)
22
- raise SmsError, "Phone number cannot begin with 0 or 1" if ['0','1'].include?(phone[0].to_s)
23
- raise SmsError, "Message cannot be blank" if message.empty?
26
+ raise InvalidPhoneNumberError, "Phone number must be ten digits" unless /\A[0-9]{10}\z/.match(phone)
27
+ raise InvalidPhoneNumberError, "Phone number cannot begin with 0 or 1" if ['0','1'].include?(phone[0].to_s)
28
+ raise InvalidMessageError, "Message cannot be blank" if message.empty?
29
+ illegal_characters = ILLEGAL_CHARACTERS.match(message).to_a
30
+ raise InvalidMessageError, "Message cannot contain the following special characters: #{illegal_characters.uniq.join(', ')}" unless illegal_characters.size.zero?
24
31
  Mblox.log "WARNING: Some characters may be lost because the message must be broken into at least 1000 sections" if message.size > (999 * MAX_SECTION_LENGTH)
25
32
  @message = (message.size > MAX_LENGTH) ? ON_MESSAGE_TOO_LONG_HANDLER[Mblox.config.on_message_too_long].call(message) : [message.dup]
26
33
  @phone = "1#{phone}"
@@ -31,23 +38,12 @@ module Mblox
31
38
  end
32
39
  private
33
40
  def commit(request_body)
34
- Mblox.log "Sending SMS to Mblox:\n#{request_body}"
35
- uri = URI.parse(Mblox.config.outbound_url)
36
- http = Net::HTTP.new(uri.host, uri.port)
37
- request = Net::HTTP::Post.new(uri.request_uri)
38
- request.body = request_body
39
- request.content_type = 'text/xml'
40
- response = http.start {|http| http.request(request) }
41
- response = response.body
42
- Mblox.log "Mblox responds with:\n#{response}"
43
- build_response(Hash.from_xml(response))
44
- end
45
-
46
- def build_response(result)
47
- result = result['NotificationRequestResult']
48
- result_header = result['NotificationResultHeader']
49
- subscriber_result = result['NotificationResultList']['NotificationResult']['SubscriberResult']
50
- "RequestResult: \"#{result_header['RequestResultCode']}:#{result_header['RequestResultText']}\" / SubscriberResult: \"#{subscriber_result['SubscriberResultCode']}:#{subscriber_result['SubscriberResultText']}\""
41
+ Mblox.log "Sending SMS to Mblox:\n#{request_body}"
42
+ request = self.class.request
43
+ request.body = request_body
44
+ response = self.class.http.start{ |http| http.request(request) }.body
45
+ Mblox.log "Mblox responds with:\n#{response}"
46
+ SmsResponse.new(response)
51
47
  end
52
48
 
53
49
  def build(message)
@@ -58,11 +54,13 @@ module Mblox
58
54
  nh.PartnerName(Mblox.config.partner_name)
59
55
  nh.PartnerPassword(Mblox.config.password)
60
56
  end
61
- nr.NotificationList(:BatchID => "1") do |nl|
62
- nl.Notification(:SequenceNumber => "1", :MessageType => "SMS") do |n|
63
- n.Message(message)
57
+ nr.NotificationList(:BatchID => 1) do |nl|
58
+ nl.Notification(:SequenceNumber => 1, :MessageType => :SMS, :Format => :UTF8) do |n|
59
+ n.Message do |m|
60
+ m.cdata!(message)
61
+ end
64
62
  n.Profile(Mblox.config.profile_id)
65
- n.SenderID(Mblox.config.sender_id, :Type => 'Shortcode')
63
+ n.SenderID(Mblox.config.sender_id, :Type => :Shortcode)
66
64
  n.Tariff(Mblox.config.tariff)
67
65
  n.Subscriber do |s|
68
66
  s.SubscriberNumber(@phone)
@@ -90,5 +88,20 @@ module Mblox
90
88
  Mblox.log "Section ##{sections} of ##{sections} contains characters #{first_char + 1} thru #{message.size} of #{message.size}"
91
89
  split_message << "(MSG #{sections}/#{sections}): #{message[first_char..-1]}"
92
90
  end
91
+
92
+ class << self
93
+ def url
94
+ @url ||= URI.parse(URI.escape(Mblox.config.outbound_url))
95
+ end
96
+ def http
97
+ @http ||= Net::HTTP.new(url.host, url.port)
98
+ end
99
+ def request
100
+ return @request if @request
101
+ @request = Net::HTTP::Post.new(url.request_uri)
102
+ @request.content_type = 'text/xml'
103
+ @request
104
+ end
105
+ end
93
106
  end
94
107
  end
@@ -0,0 +1,69 @@
1
+ require 'active_model/serialization'
2
+ require 'active_model/serializers/xml.rb'
3
+
4
+ require 'active_model/callbacks'
5
+ require 'active_model/validator'
6
+ require 'active_model/naming'
7
+ require 'active_model/translation'
8
+ require 'active_model/validations'
9
+ require 'active_model/errors'
10
+
11
+ module Mblox
12
+ class SmsResponse
13
+ class MissingExpectedXmlContentError < StandardError; end
14
+ class Result
15
+ include ActiveModel::Validations
16
+ validates_presence_of :text, :code, :message => "%{attribute} cannot be blank"
17
+ validates_numericality_of :code, :only_integer => true, :allow_nil => true, :message => "%{attribute} must be an integer"
18
+
19
+ attr_reader :code, :text
20
+ def initialize(code, text)
21
+ @code, @text = (code.to_i.to_s == code ? code.to_i : code), text
22
+ end
23
+
24
+ def is_ok?
25
+ 0 == @code
26
+ end
27
+
28
+ def ==(rhs)
29
+ code == rhs.code && text == rhs.text
30
+ end
31
+
32
+ UNROUTABLE_TEXT = "MsipRejectCode=29 Number unroutable:2e Do not retry:2e"
33
+ UNROUTABLE = new(10, UNROUTABLE_TEXT)
34
+ end
35
+
36
+ attr_reader :request, :result, :subscriber_result
37
+ def initialize(xml)
38
+ data = Hash.from_xml(xml)
39
+ data = data['NotificationRequestResult']
40
+ raise MissingExpectedXmlContentError, "Xml should have contained a 'NotificationRequestResult' node, but was #{xml}" if data.blank?
41
+ header = data['NotificationResultHeader']
42
+ raise MissingExpectedXmlContentError, "Xml should have contained a 'NotificationRequestResult' -> 'NotificationResultHeader' node, but was #{xml}" if header.blank?
43
+ @request = Result.new(header['RequestResultCode'], header['RequestResultText'])
44
+ @request = nil unless @request.valid?
45
+
46
+ result_list = data['NotificationResultList']
47
+ raise MissingExpectedXmlContentError, "Xml should have contained a 'NotificationRequestResult' -> 'NotificationResultList' node, but was #{xml}" if result_list.blank?
48
+ result_list = result_list['NotificationResult']
49
+ raise MissingExpectedXmlContentError, "Xml should have contained a 'NotificationRequestResult' -> 'NotificationResultList' => 'NotificationResult' node, but was #{xml}" if result_list.blank?
50
+ @result = Result.new(result_list['NotificationResultCode'], result_list['NotificationResultText'])
51
+ @result = nil unless @result.valid?
52
+
53
+ if @result.is_ok?
54
+ result_list = result_list['SubscriberResult']
55
+ raise MissingExpectedXmlContentError, "Xml should have contained a 'NotificationRequestResult' -> 'NotificationResultList' => 'NotificationResult' -> 'SubscriberResult' node, but was #{xml}" if result_list.blank?
56
+ @subscriber_result = Result.new(result_list['SubscriberResultCode'], result_list['SubscriberResultText'])
57
+ @subscriber_result = nil unless @subscriber_result.valid?
58
+ end
59
+ end
60
+
61
+ def is_ok?
62
+ @request.is_ok? && @result.is_ok? && @subscriber_result.is_ok?
63
+ end
64
+
65
+ def is_unroutable?
66
+ @request.is_ok? && @result.is_ok? && Result::UNROUTABLE == @subscriber_result
67
+ end
68
+ end
69
+ end
data/lib/mblox/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Mblox
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
3
3
  end
data/mblox.gemspec CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
22
22
  spec.add_development_dependency "rake"
23
23
  spec.add_development_dependency "rspec"
24
24
 
25
+ spec.add_runtime_dependency 'activemodel'
25
26
  spec.add_runtime_dependency 'activesupport'
26
27
  spec.add_runtime_dependency 'addressable'
27
28
  spec.add_runtime_dependency 'builder'
@@ -1,27 +1,59 @@
1
1
  require "spec_helper"
2
2
 
3
- describe "configuration" do
4
- describe "on_message_too_long" do
5
- it "should default to :raise_error" do
3
+ describe Mblox::Configuration do
4
+ describe "logger" do
5
+ before(:each) do
6
6
  Mblox.reset_configuration
7
- expect(Mblox.config.on_message_too_long).to eq(:raise_error)
8
7
  end
9
8
 
10
- it "should allow the value :truncate" do
11
- expect { Mblox.config.on_message_too_long = :truncate }.to_not raise_error
9
+ after(:all) do
10
+ set_configuration
11
+ end
12
+
13
+ [:fatal, :error, :warn, :info, :debug].each do |val|
14
+ it "should allow log level ':#{val}'" do
15
+ Mblox.config.log_at val
16
+ Mblox.config.logger = ::Logger.new('/dev/null')
17
+ expect { Mblox.log "Some info" }.to_not raise_error
18
+ end
19
+ end
20
+
21
+ it "should default to log level debug" do
22
+ Mblox.config.log_level.should eq(:debug)
23
+ expect { Mblox.log "Some debug info" }.to_not raise_error
24
+ end
25
+
26
+ it "should not allow log level news when the logger is created after log level is set" do
27
+ Mblox.config.log_at :news
28
+ expect { Mblox.config.logger = ::Logger.new(STDOUT)}.to raise_error(ArgumentError, "Mblox log level must be set to :fatal, :error, :warn, :info or :debug")
29
+ expect { Mblox.log "Some news" }.to_not raise_error
30
+ end
31
+
32
+ it "should not allow log level news when the logger is created before log level is set and should remain in a valid state" do
33
+ Mblox.config.logger = ::Logger.new("/dev/null")
34
+ expect { Mblox.config.log_at :news }.to raise_error(ArgumentError, "Mblox log level must be set to :fatal, :error, :warn, :info or :debug")
35
+ Mblox.config.log_level.should eq(:debug)
36
+ expect { Mblox.log "Some news" }.to_not raise_error
12
37
  end
38
+ end
13
39
 
14
- it "should allow the value :split" do
15
- expect { Mblox.config.on_message_too_long = :split }.to_not raise_error
40
+ describe "on_message_too_long" do
41
+ it "should default to :raise_error" do
42
+ Mblox.reset_configuration
43
+ Mblox.config.on_message_too_long.should eq(:raise_error)
16
44
  end
17
45
 
18
- it "should allow the value :raise_error" do
19
- expect { Mblox.config.on_message_too_long = :raise_error }.to_not raise_error
46
+ [:raise_error, :split, :truncate].each do |val|
47
+ it "should allow the value ':#{val}'" do
48
+ expect { Mblox.config.on_message_too_long = val }.to_not raise_error
49
+ Mblox.config.on_message_too_long.should eq(val)
50
+ end
20
51
  end
21
52
 
22
53
  it "should not allow other values and should remain in a valid state" do
54
+ original = Mblox.config.on_message_too_long
23
55
  expect { Mblox.config.on_message_too_long = :do_nothing }.to raise_error(ArgumentError, "Mblox.config.on_message_too_long must be either :truncate, :split or :raise_error")
24
- expect(Mblox.config.on_message_too_long).to eq(:raise_error)
56
+ Mblox.config.on_message_too_long.should eq(original)
25
57
  end
26
58
  end
27
59
  end
@@ -0,0 +1,62 @@
1
+ require "spec_helper"
2
+
3
+ describe Mblox::SmsResponse::Result do
4
+ describe "code" do
5
+ it "cannot be blank" do
6
+ result = described_class.new(nil, "123")
7
+ result.valid?
8
+ result.errors[:code].should include("Code cannot be blank")
9
+ end
10
+
11
+ it "must be a number" do
12
+ result = described_class.new('abc', "123")
13
+ result.valid?
14
+ result.errors[:code].should include("Code must be an integer")
15
+ end
16
+
17
+ it "must be an integer" do
18
+ result = described_class.new(3.14159, "123")
19
+ result.valid?
20
+ result.errors[:code].should include("Code must be an integer")
21
+ end
22
+ end
23
+
24
+ describe "text" do
25
+ it "cannot be blank" do
26
+ result = described_class.new(0, '')
27
+ result.valid?
28
+ result.errors[:text].should include("Text cannot be blank")
29
+ end
30
+ end
31
+
32
+ describe "is_ok?" do
33
+ it "is true for code 0" do
34
+ described_class.new(0, "123").is_ok?.should be_true
35
+ end
36
+
37
+ 10.times do |i|
38
+ it "is false for code #{i+1}" do
39
+ described_class.new(i+1, "123").is_ok?.should be_false
40
+ end
41
+ end
42
+ end
43
+
44
+ describe "==" do
45
+ it "should be true if code and text are the same" do
46
+ lhs = described_class.new(0, 'OK')
47
+ rhs = described_class.new(0, 'OK')
48
+ (lhs == rhs).should be_true
49
+ end
50
+
51
+ it "should be false if code does not match" do
52
+ lhs = described_class.new(0, 'OK')
53
+ rhs = described_class.new(4, 'OK')
54
+ (lhs == rhs).should be_false
55
+ end
56
+ it "should be false if text does not match" do
57
+ lhs = described_class.new(0, 'OK')
58
+ rhs = described_class.new(0, '__OK__')
59
+ (lhs == rhs).should be_false
60
+ end
61
+ end
62
+ end
data/spec/sms_spec.rb CHANGED
@@ -1,91 +1,137 @@
1
+ # encoding: UTF-8
1
2
  require "spec_helper"
2
3
 
3
- describe "phone number" do
4
- it "should be 10 digits" do
5
- expect { Mblox::Sms.new("2"*9, the_message) }.to raise_error(Mblox::SmsError, "Phone number must be ten digits")
6
- expect { Mblox::Sms.new("2"*10, the_message) }.to_not raise_error
7
- expect { Mblox::Sms.new("2"*11, the_message) }.to raise_error(Mblox::SmsError, "Phone number must be ten digits")
4
+ describe Mblox::Sms do
5
+ def the_message
6
+ "Mblox gem test sent at #{Time.now}"
8
7
  end
9
-
10
- it "should not start with 0 or 1" do
11
- expect { Mblox::Sms.new("1"+"2"*9, the_message) }.to raise_error(Mblox::SmsError, "Phone number cannot begin with 0 or 1")
12
- expect { Mblox::Sms.new("0"+"2"*9, the_message) }.to raise_error(Mblox::SmsError, "Phone number cannot begin with 0 or 1")
8
+ before(:all) do
9
+ Mblox.reset_configuration
10
+ set_configuration
13
11
  end
12
+ describe "phone number" do
13
+ it "should be 10 digits" do
14
+ expect { Mblox::Sms.new("2"*9, the_message) }.to raise_error(Mblox::Sms::InvalidPhoneNumberError, "Phone number must be ten digits")
15
+ expect { Mblox::Sms.new("2"*10, the_message) }.to_not raise_error
16
+ expect { Mblox::Sms.new("2"*11, the_message) }.to raise_error(Mblox::Sms::InvalidPhoneNumberError, "Phone number must be ten digits")
17
+ end
14
18
 
15
- it "should be safe from changing" do
16
- number = TEST_NUMBER.to_s
17
- mblox = Mblox::Sms.new(number,the_message)
18
- number[1..3] = ''
19
- expect(mblox.phone).to eq("1#{TEST_NUMBER}")
20
- end
21
- end
19
+ it "should not start with 0 or 1" do
20
+ expect { Mblox::Sms.new("1"+"2"*9, the_message) }.to raise_error(Mblox::Sms::InvalidPhoneNumberError, "Phone number cannot begin with 0 or 1")
21
+ expect { Mblox::Sms.new("0"+"2"*9, the_message) }.to raise_error(Mblox::Sms::InvalidPhoneNumberError, "Phone number cannot begin with 0 or 1")
22
+ end
22
23
 
23
- describe "message" do
24
- it "cannot be blank" do
25
- expect { Mblox::Sms.new("2"*10, "") }.to raise_error(Mblox::SmsError, "Message cannot be blank")
24
+ it "should be safe from changing" do
25
+ number = TEST_NUMBER.to_s
26
+ mblox = Mblox::Sms.new(number,the_message)
27
+ number[1..3] = ''
28
+ mblox.phone.should eq("1#{TEST_NUMBER}")
29
+ end
26
30
  end
27
31
 
28
- it "can be 160 characters long" do
29
- expect { Mblox::Sms.new("2"*10, "A"*160) }.to_not raise_error
30
- end
32
+ describe "message" do
33
+ it "cannot be blank" do
34
+ expect { Mblox::Sms.new(LANDLINE, "") }.to raise_error(Mblox::Sms::InvalidMessageError, "Message cannot be blank")
35
+ end
31
36
 
32
- it "will be truncated when the message is longer than 160 characters if configured to do so" do
33
- message = "A"+"ABCDEFGHIJ"*16
34
- Mblox.config.on_message_too_long = :truncate
35
- expect { @mblox = Mblox::Sms.new("2"*10, message) }.to_not raise_error
36
- expect(@mblox.message).to eq([message[0,160]])
37
- end
37
+ it "can be 160 characters long" do
38
+ expect { Mblox::Sms.new(LANDLINE, "A"*160) }.to_not raise_error
39
+ end
38
40
 
39
- it "cannot be longer than 160 characters if configured to raise error" do
40
- Mblox.config.on_message_too_long = :raise_error
41
- expect { Mblox::Sms.new("2"*10, "A"*161) }.to raise_error(Mblox::SmsError, "Message cannot be longer than 160 characters")
42
- end
41
+ it "will be truncated when the message is longer than 160 characters if configured to do so" do
42
+ message = "A"+"ABCDEFGHIJ"*16
43
+ Mblox.config.on_message_too_long = :truncate
44
+ expect { @mblox = Mblox::Sms.new(LANDLINE, message) }.to_not raise_error
45
+ @mblox.message.should eq([message[0,160]])
46
+ end
43
47
 
44
- it "should be split into multiple messages when longer than 160 characters if configured to split and even split" do
45
- message = "ABCDEFGHIJ"*58
46
- Mblox.config.on_message_too_long = :split
47
- expect { @mblox = Mblox::Sms.new("2"*10, message) }.to_not raise_error
48
- expect(@mblox.message).to eq(["(MSG 1/4): #{message[0,145]}", "(MSG 2/4): #{message[145,145]}", "(MSG 3/4): #{message[290,145]}", "(MSG 4/4): #{message[435,145]}"])
49
- expect(@mblox.send).to eq(Array.new(4, result_unroutable))
50
- end
48
+ it "cannot be longer than 160 characters if configured to raise error" do
49
+ Mblox.config.on_message_too_long = :raise_error
50
+ expect { Mblox::Sms.new(LANDLINE, "A"*161) }.to raise_error(Mblox::Sms::InvalidMessageError, "Message cannot be longer than 160 characters")
51
+ end
51
52
 
52
- it "should be split into multiple messages when longer than 160 characters if configured to split and not even split" do
53
- message = "ABCDEFGHIJ"*32
54
- Mblox.config.on_message_too_long = :split
55
- expect { @mblox = Mblox::Sms.new("2"*10, message) }.to_not raise_error
56
- expect(@mblox.message).to eq(["(MSG 1/3): #{message[0,145]}", "(MSG 2/3): #{message[145,145]}", "(MSG 3/3): #{message[290..-1]}"])
57
- expect(@mblox.send).to eq(Array.new(3, result_unroutable))
58
- end
53
+ it "should be split into multiple messages when longer than 160 characters if configured to split and even split" do
54
+ message = "ABCDEFGHIJ"*58
55
+ Mblox.config.on_message_too_long = :split
56
+ expect { @mblox = Mblox::Sms.new(LANDLINE, message) }.to_not raise_error
57
+ @mblox.message.should eq(["(MSG 1/4): #{message[0,145]}", "(MSG 2/4): #{message[145,145]}", "(MSG 3/4): #{message[290,145]}", "(MSG 4/4): #{message[435,145]}"])
58
+ response = @mblox.send
59
+ response.count.should eq(4)
60
+ response.each { |r| r.is_unroutable?.should be_true }
61
+ end
59
62
 
60
- it "should be safe from changing when short" do
61
- msg = the_message
62
- mblox = Mblox::Sms.new(TEST_NUMBER,msg)
63
- msg[1..3] = ''
64
- expect(mblox.message).to eq([the_message])
65
- end
63
+ it "should be split into multiple messages when longer than 160 characters if configured to split and not even split" do
64
+ message = "ABCDEFGHIJ"*32
65
+ Mblox.config.on_message_too_long = :split
66
+ expect { @mblox = Mblox::Sms.new(LANDLINE, message) }.to_not raise_error
67
+ @mblox.message.should eq(["(MSG 1/3): #{message[0,145]}", "(MSG 2/3): #{message[145,145]}", "(MSG 3/3): #{message[290..-1]}"])
68
+ response = @mblox.send
69
+ response.count.should eq(3)
70
+ response.each { |r| r.is_unroutable?.should be_true }
71
+ end
66
72
 
67
- it "should be safe from changing when long" do
68
- msg = the_message * 10
69
- mblox = Mblox::Sms.new(TEST_NUMBER,msg)
70
- msg[1..3] = ''
71
- expect(mblox.message[0][11, 20]).to eq(the_message[0,20])
72
- end
73
- end
73
+ it "should be safe from changing when short" do
74
+ msg = the_message
75
+ mblox = Mblox::Sms.new(TEST_NUMBER,msg)
76
+ msg[1..3] = ''
77
+ mblox.message.should eq([the_message])
78
+ end
74
79
 
75
- describe "SMS messages" do
76
- it "should be sent when the phone number is a Fixnum" do
77
- expect(Mblox::Sms.new(TEST_NUMBER.to_i,the_message).send).to eq([result_ok])
78
- end
80
+ it "should be safe from changing when long when configured to split" do
81
+ Mblox.config.on_message_too_long = :split
82
+ msg = the_message * 10
83
+ mblox = Mblox::Sms.new(TEST_NUMBER,msg)
84
+ msg[1..3] = ''
85
+ mblox.message[0][11, 20].should eq(the_message[0,20])
86
+ end
79
87
 
80
- it "should be sent when the phone number is a String" do
81
- expect(Mblox::Sms.new(TEST_NUMBER.to_s,the_message).send).to eq([result_ok])
88
+ it "should be safe from changing when long when configured to truncate" do
89
+ Mblox.config.on_message_too_long = :truncate
90
+ msg = the_message * 10
91
+ mblox = Mblox::Sms.new(TEST_NUMBER,msg)
92
+ msg[1..3] = ''
93
+ mblox.message[0][0, 20].should eq(the_message[0,20])
94
+ end
82
95
  end
83
96
 
84
- it "should allow 160-character messages" do
85
- expect(Mblox::Sms.new(TEST_NUMBER,"A"*160).send).to eq([result_ok])
86
- end
97
+ describe "SMS messages" do
98
+ def expect_ok_response(response)
99
+ response.is_ok?.should be_true
100
+ response.is_unroutable?.should be_false
101
+ end
102
+
103
+ it "should be sent when the phone number is a Fixnum" do
104
+ response = Mblox::Sms.new(TEST_NUMBER.to_i,the_message).send
105
+ response.size.should eq(1)
106
+ expect_ok_response(response.first)
107
+ end
108
+
109
+ it "should be sent when the phone number is a String" do
110
+ response = Mblox::Sms.new(TEST_NUMBER.to_s,the_message).send
111
+ response.size.should eq(1)
112
+ expect_ok_response(response.first)
113
+ end
114
+
115
+ it "should allow 160-character messages" do
116
+ response = Mblox::Sms.new(TEST_NUMBER,"A"*160).send
117
+ response.size.should eq(1)
118
+ expect_ok_response(response.first)
119
+ end
120
+
121
+ it "should be unroutable when sent to a landline" do
122
+ response = Mblox::Sms.new(LANDLINE,the_message).send
123
+ response.size.should eq(1)
124
+ response.first.is_unroutable?.should be_true, "#{response.first.inspect} should have been unroutable"
125
+ response.first.is_ok?.should be_false
126
+ end
87
127
 
88
- it "should fail when sent to a landline" do
89
- expect(Mblox::Sms.new("6176354500",the_message).send).to eq([result_unroutable])
128
+ "\r\n!\"#$\%&'\(\)*+,-.\/:;<=>?@_£¤¥§¿iÄÅÆÇÉÑÖØÜßáäåæèéìñòöøùü\tí¡ ".each_char do |i|
129
+ it "allows the special char #{i}, correctly escaping illegal XML characters where necessary" do
130
+ response = Mblox::Sms.new(LANDLINE,"#{the_message}#{i}#{the_message}").send
131
+ response.size.should eq(1)
132
+ response.first.is_ok?.should be_false
133
+ response.first.is_unroutable?.should be_true
134
+ end
135
+ end
90
136
  end
91
137
  end
data/spec/spec_helper.rb CHANGED
@@ -15,21 +15,8 @@ def set_configuration
15
15
  end
16
16
  end
17
17
 
18
- set_configuration
19
-
20
18
  TEST_NUMBER = CONFIG['test_number']
21
-
22
- def the_message
23
- "Mblox gem test sent at #{Time.now}"
24
- end
25
-
26
- def result_ok
27
- "RequestResult: \"0:OK\" / SubscriberResult: \"0:OK\""
28
- end
29
-
30
- def result_unroutable
31
- "RequestResult: \"0:OK\" / SubscriberResult: \"10:MsipRejectCode=29 Number unroutable:2e Do not retry:2e\""
32
- end
19
+ LANDLINE = 6176354500
33
20
 
34
21
  module Mblox
35
22
  class << self
@@ -38,3 +25,7 @@ module Mblox
38
25
  end
39
26
  end
40
27
  end
28
+
29
+ RSpec.configure do |config|
30
+ config.order = "random"
31
+ end
metadata CHANGED
@@ -1,20 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mblox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
5
- prerelease:
4
+ version: 0.1.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Isaac Betesh
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-08-09 00:00:00.000000000 Z
11
+ date: 2013-10-09 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: bundler
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
17
  - - ~>
20
18
  - !ruby/object:Gem::Version
@@ -22,7 +20,6 @@ dependencies:
22
20
  type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
24
  - - ~>
28
25
  - !ruby/object:Gem::Version
@@ -30,7 +27,6 @@ dependencies:
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: rake
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
31
  - - ! '>='
36
32
  - !ruby/object:Gem::Version
@@ -38,7 +34,6 @@ dependencies:
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
38
  - - ! '>='
44
39
  - !ruby/object:Gem::Version
@@ -46,7 +41,6 @@ dependencies:
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: rspec
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
45
  - - ! '>='
52
46
  - !ruby/object:Gem::Version
@@ -54,7 +48,20 @@ dependencies:
54
48
  type: :development
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activemodel
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
58
65
  requirements:
59
66
  - - ! '>='
60
67
  - !ruby/object:Gem::Version
@@ -62,7 +69,6 @@ dependencies:
62
69
  - !ruby/object:Gem::Dependency
63
70
  name: activesupport
64
71
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
72
  requirements:
67
73
  - - ! '>='
68
74
  - !ruby/object:Gem::Version
@@ -70,7 +76,6 @@ dependencies:
70
76
  type: :runtime
71
77
  prerelease: false
72
78
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
79
  requirements:
75
80
  - - ! '>='
76
81
  - !ruby/object:Gem::Version
@@ -78,7 +83,6 @@ dependencies:
78
83
  - !ruby/object:Gem::Dependency
79
84
  name: addressable
80
85
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
86
  requirements:
83
87
  - - ! '>='
84
88
  - !ruby/object:Gem::Version
@@ -86,7 +90,6 @@ dependencies:
86
90
  type: :runtime
87
91
  prerelease: false
88
92
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
93
  requirements:
91
94
  - - ! '>='
92
95
  - !ruby/object:Gem::Version
@@ -94,7 +97,6 @@ dependencies:
94
97
  - !ruby/object:Gem::Dependency
95
98
  name: builder
96
99
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
100
  requirements:
99
101
  - - ! '>='
100
102
  - !ruby/object:Gem::Version
@@ -102,7 +104,6 @@ dependencies:
102
104
  type: :runtime
103
105
  prerelease: false
104
106
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
107
  requirements:
107
108
  - - ! '>='
108
109
  - !ruby/object:Gem::Version
@@ -124,43 +125,36 @@ files:
124
125
  - lib/mblox.rb
125
126
  - lib/mblox/configuration.rb
126
127
  - lib/mblox/sms.rb
127
- - lib/mblox/sms_error.rb
128
+ - lib/mblox/sms_response.rb
128
129
  - lib/mblox/version.rb
129
130
  - mblox.gemspec
130
131
  - spec/configuration_spec.rb
131
- - spec/log_spec.rb
132
+ - spec/sms_response_result_spec.rb
132
133
  - spec/sms_spec.rb
133
134
  - spec/spec_helper.rb
134
135
  homepage: ''
135
136
  licenses:
136
137
  - MIT
138
+ metadata: {}
137
139
  post_install_message:
138
140
  rdoc_options: []
139
141
  require_paths:
140
142
  - lib
141
143
  required_ruby_version: !ruby/object:Gem::Requirement
142
- none: false
143
144
  requirements:
144
145
  - - ! '>='
145
146
  - !ruby/object:Gem::Version
146
147
  version: '0'
147
- segments:
148
- - 0
149
- hash: 965711471
150
148
  required_rubygems_version: !ruby/object:Gem::Requirement
151
- none: false
152
149
  requirements:
153
150
  - - ! '>='
154
151
  - !ruby/object:Gem::Version
155
152
  version: '0'
156
- segments:
157
- - 0
158
- hash: 965711471
159
153
  requirements: []
160
154
  rubyforge_project:
161
- rubygems_version: 1.8.24
155
+ rubygems_version: 2.1.5
162
156
  signing_key:
163
- specification_version: 3
157
+ specification_version: 4
164
158
  summary: ! '# Mblox This gem is for subscribers to Mblox to send SMS messages. ##
165
159
  Installation Add this line to your application''s Gemfile: gem ''mblox'' And
166
160
  then execute: $ bundle Or install it yourself as: $ gem install mblox ## Usage Configuration Mblox.configure
@@ -186,6 +180,6 @@ summary: ! '# Mblox This gem is for subscribers to Mblox to send SMS messages.
186
180
  5. Create new Pull Request'
187
181
  test_files:
188
182
  - spec/configuration_spec.rb
189
- - spec/log_spec.rb
183
+ - spec/sms_response_result_spec.rb
190
184
  - spec/sms_spec.rb
191
185
  - spec/spec_helper.rb
@@ -1,4 +0,0 @@
1
- module Mblox
2
- class SmsError < ArgumentError
3
- end
4
- end
data/spec/log_spec.rb DELETED
@@ -1,35 +0,0 @@
1
- require "spec_helper"
2
- require "logger"
3
-
4
- describe "logger" do
5
- before(:each) do
6
- Mblox.reset_configuration
7
- end
8
-
9
- after(:all) do
10
- set_configuration
11
- end
12
-
13
- it "should allow log level info" do
14
- Mblox.config.log_at :info
15
- Mblox.config.logger = ::Logger.new('/dev/null')
16
- expect { Mblox.log "Some info" }.to_not raise_error
17
- end
18
-
19
- it "should default to log level debug" do
20
- expect(Mblox.config.log_level).to eq(:debug)
21
- expect { Mblox.log "Some debug info" }.to_not raise_error
22
- end
23
-
24
- it "should not allow log level news when the logger is created after log level is set" do
25
- Mblox.config.log_at :news
26
- expect { Mblox.config.logger = ::Logger.new(STDOUT)}.to raise_error(ArgumentError, "Mblox log level must be set to :fatal, :error, :warn, :info or :debug")
27
- expect { Mblox.log "Some news" }.to_not raise_error
28
- end
29
-
30
- it "should not allow log level news when the logger is created before log level is set and should remain in a valid state" do
31
- Mblox.config.logger = ::Logger.new("/dev/null")
32
- expect { Mblox.config.log_at :news }.to raise_error(ArgumentError, "Mblox log level must be set to :fatal, :error, :warn, :info or :debug")
33
- expect { Mblox.log "Some news" }.to_not raise_error
34
- end
35
- end