mblox 0.0.3 → 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.
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