actionsms 0.0.2

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f711e9e7d3ed8064ea278d3bdb378005edde4af7
4
+ data.tar.gz: 4de6283fc43d1a7422cf4ad0d8beb40150e2c1b1
5
+ SHA512:
6
+ metadata.gz: 7a5cf86cd25de6c9033df1bdd51014461580a7ab250ea7b2a82dd3dc2aebdc181bffb477961fb825b45ed80706e11da0512e29f9a05eb6939a92f9d7c41c23f3
7
+ data.tar.gz: 67d0492a4e5bf4b7ee048d0be74ae7237a8de18bfd978f5138c5e57db6fba015c90bebed749027938e7adccb93b4d51e3a83e9ced1c8c16a337e15d5a70ec134
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "activesupport", ">= 3.2"
4
+
5
+ group :development do
6
+ gem 'rspec', '~>3.2.0'
7
+ gem 'rdoc'
8
+ gem 'bundler'
9
+ gem 'jeweler'
10
+ end
11
+
12
+ group :test do
13
+ gem 'webmock'
14
+ end
@@ -0,0 +1,88 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activesupport (4.2.1)
5
+ i18n (~> 0.7)
6
+ json (~> 1.7, >= 1.7.7)
7
+ minitest (~> 5.1)
8
+ thread_safe (~> 0.3, >= 0.3.4)
9
+ tzinfo (~> 1.1)
10
+ addressable (2.3.8)
11
+ builder (3.2.2)
12
+ crack (0.4.2)
13
+ safe_yaml (~> 1.0.0)
14
+ descendants_tracker (0.0.4)
15
+ thread_safe (~> 0.3, >= 0.3.1)
16
+ diff-lcs (1.2.5)
17
+ faraday (0.9.1)
18
+ multipart-post (>= 1.2, < 3)
19
+ git (1.2.9.1)
20
+ github_api (0.12.3)
21
+ addressable (~> 2.3)
22
+ descendants_tracker (~> 0.0.4)
23
+ faraday (~> 0.8, < 0.10)
24
+ hashie (>= 3.3)
25
+ multi_json (>= 1.7.5, < 2.0)
26
+ nokogiri (~> 1.6.3)
27
+ oauth2
28
+ hashie (3.4.1)
29
+ highline (1.7.1)
30
+ i18n (0.7.0)
31
+ jeweler (2.0.1)
32
+ builder
33
+ bundler (>= 1.0)
34
+ git (>= 1.2.5)
35
+ github_api
36
+ highline (>= 1.6.15)
37
+ nokogiri (>= 1.5.10)
38
+ rake
39
+ rdoc
40
+ json (1.8.2)
41
+ jwt (1.4.1)
42
+ mini_portile (0.6.2)
43
+ minitest (5.5.1)
44
+ multi_json (1.11.0)
45
+ multi_xml (0.5.5)
46
+ multipart-post (2.0.0)
47
+ nokogiri (1.6.6.2)
48
+ mini_portile (~> 0.6.0)
49
+ oauth2 (1.0.0)
50
+ faraday (>= 0.8, < 0.10)
51
+ jwt (~> 1.0)
52
+ multi_json (~> 1.3)
53
+ multi_xml (~> 0.5)
54
+ rack (~> 1.2)
55
+ rack (1.6.0)
56
+ rake (10.4.2)
57
+ rdoc (4.2.0)
58
+ rspec (3.2.0)
59
+ rspec-core (~> 3.2.0)
60
+ rspec-expectations (~> 3.2.0)
61
+ rspec-mocks (~> 3.2.0)
62
+ rspec-core (3.2.3)
63
+ rspec-support (~> 3.2.0)
64
+ rspec-expectations (3.2.1)
65
+ diff-lcs (>= 1.2.0, < 2.0)
66
+ rspec-support (~> 3.2.0)
67
+ rspec-mocks (3.2.1)
68
+ diff-lcs (>= 1.2.0, < 2.0)
69
+ rspec-support (~> 3.2.0)
70
+ rspec-support (3.2.2)
71
+ safe_yaml (1.0.4)
72
+ thread_safe (0.3.5)
73
+ tzinfo (1.2.2)
74
+ thread_safe (~> 0.1)
75
+ webmock (1.21.0)
76
+ addressable (>= 2.3.6)
77
+ crack (>= 0.3.2)
78
+
79
+ PLATFORMS
80
+ ruby
81
+
82
+ DEPENDENCIES
83
+ activesupport (>= 3.2)
84
+ bundler
85
+ jeweler
86
+ rdoc
87
+ rspec (~> 3.2.0)
88
+ webmock
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2014 Roman Shterenzon
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,50 @@
1
+ # ActionSMS
2
+
3
+ ActionSMS was inspired by ActionMailer and it aims to provide a unified interface for using an SMS provider.
4
+
5
+ ## Synopsis
6
+
7
+ ```ruby
8
+ # config/initializers/sms.rb
9
+ require 'sms/method/twilio'
10
+ Sms.delivery_method = Sms::Method::Twilio.new(account_sid, auth_token, default_from)
11
+
12
+ ```
13
+
14
+ ```ruby
15
+ # app/models/user.rb
16
+ require 'actionsms'
17
+ after_create do
18
+ message = Sms::Message.new(from: '123', to: phone, text: 'Thanks for signing up!')
19
+ message.deliver
20
+ end
21
+ ```
22
+
23
+ Example controller receiving SMS:
24
+ ```ruby
25
+ require 'sms'
26
+
27
+ class SmsController < ActionController::Metal
28
+ def receive
29
+ self.content_type = 'text/plain'
30
+ unless %w[from to text].all? { |key| params.key?(key) }
31
+ self.status = 400
32
+ self.response_body = "Invalid Request\n"
33
+ return
34
+ end
35
+ SmsReceiver.receive(params)
36
+ self.response_body = ''
37
+ end
38
+ end
39
+
40
+ class SmsReceiver < Sms
41
+ def receive(sms)
42
+ Rails.logger.info "SMS: #{sms.inspect}"
43
+ end
44
+ end
45
+ ```
46
+
47
+ ## TODO
48
+
49
+ * Railtie for doing things like config.action\_sms.delivery_method = :file
50
+ * Configurable place for the file
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "actionsms"
18
+ gem.homepage = "http://github.com/romanbsd/actionsms"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Like ActionMailer, but for SMS}
21
+ gem.description = gem.summary
22
+ gem.email = "romanbsd@yahoo.com"
23
+ gem.authors = ["Roman Shterenzon"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rspec/core'
29
+ require 'rspec/core/rake_task'
30
+ RSpec::Core::RakeTask.new(:spec) do |spec|
31
+ spec.pattern = FileList['spec/**/*_spec.rb']
32
+ end
33
+
34
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
35
+ spec.pattern = 'spec/**/*_spec.rb'
36
+ spec.rcov = true
37
+ end
38
+
39
+ task :default => :spec
40
+
41
+ require 'rdoc/task'
42
+ Rake::RDocTask.new do |rdoc|
43
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
44
+
45
+ rdoc.rdoc_dir = 'rdoc'
46
+ rdoc.title = "actionsms #{version}"
47
+ rdoc.rdoc_files.include('README*')
48
+ rdoc.rdoc_files.include('lib/**/*.rb')
49
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.2
@@ -0,0 +1,73 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+ # stub: actionsms 0.0.2 ruby lib
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "actionsms"
9
+ s.version = "0.0.2"
10
+
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
+ s.require_paths = ["lib"]
13
+ s.authors = ["Roman Shterenzon"]
14
+ s.date = "2015-04-12"
15
+ s.description = "Like ActionMailer, but for SMS"
16
+ s.email = "romanbsd@yahoo.com"
17
+ s.extra_rdoc_files = [
18
+ "LICENSE.txt",
19
+ "README.md"
20
+ ]
21
+ s.files = [
22
+ ".rspec",
23
+ "Gemfile",
24
+ "Gemfile.lock",
25
+ "LICENSE.txt",
26
+ "README.md",
27
+ "Rakefile",
28
+ "VERSION",
29
+ "actionsms.gemspec",
30
+ "lib/actionsms.rb",
31
+ "lib/sms.rb",
32
+ "lib/sms/log_subscriber.rb",
33
+ "lib/sms/message.rb",
34
+ "lib/sms/method/bezeq.rb",
35
+ "lib/sms/method/file.rb",
36
+ "lib/sms/method/gsm.rb",
37
+ "lib/sms/method/kannel.rb",
38
+ "lib/sms/method/twilio.rb",
39
+ "spec/sms/message_spec.rb",
40
+ "spec/sms/method/bezeq_spec.rb",
41
+ "spec/sms_spec.rb",
42
+ "spec/spec_helper.rb"
43
+ ]
44
+ s.homepage = "http://github.com/romanbsd/actionsms"
45
+ s.licenses = ["MIT"]
46
+ s.rubygems_version = "2.4.6"
47
+ s.summary = "Like ActionMailer, but for SMS"
48
+
49
+ if s.respond_to? :specification_version then
50
+ s.specification_version = 4
51
+
52
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
53
+ s.add_runtime_dependency(%q<activesupport>, [">= 3.2"])
54
+ s.add_development_dependency(%q<rspec>, ["~> 3.2.0"])
55
+ s.add_development_dependency(%q<rdoc>, [">= 0"])
56
+ s.add_development_dependency(%q<bundler>, [">= 0"])
57
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
58
+ else
59
+ s.add_dependency(%q<activesupport>, [">= 3.2"])
60
+ s.add_dependency(%q<rspec>, ["~> 3.2.0"])
61
+ s.add_dependency(%q<rdoc>, [">= 0"])
62
+ s.add_dependency(%q<bundler>, [">= 0"])
63
+ s.add_dependency(%q<jeweler>, [">= 0"])
64
+ end
65
+ else
66
+ s.add_dependency(%q<activesupport>, [">= 3.2"])
67
+ s.add_dependency(%q<rspec>, ["~> 3.2.0"])
68
+ s.add_dependency(%q<rdoc>, [">= 0"])
69
+ s.add_dependency(%q<bundler>, [">= 0"])
70
+ s.add_dependency(%q<jeweler>, [">= 0"])
71
+ end
72
+ end
73
+
@@ -0,0 +1 @@
1
+ require 'sms'
@@ -0,0 +1,83 @@
1
+ class Sms
2
+
3
+ # Subclasses need to implement this method in order to handle incoming SMS.
4
+ # It should return the received message.
5
+ #
6
+ # @abstract
7
+ # @param [Sms::Message] sms
8
+ def receive(sms)
9
+ raise NotImplementedError.new('Need to subclass and implement')
10
+ end
11
+
12
+ @@delivery_notification_observers = []
13
+
14
+ class << self
15
+ def delivery_method=(obj)
16
+ @@delivery_method = obj
17
+ end
18
+
19
+ def delivery_method
20
+ @@delivery_method
21
+ end
22
+
23
+ # The observer needs to respond to a single method #delivered_sms(sms)
24
+ # which receives the sms that is sent.
25
+ def register_observer(observer)
26
+ unless @@delivery_notification_observers.include?(observer)
27
+ @@delivery_notification_observers << observer
28
+ end
29
+ end
30
+
31
+ def unregister_observer(observer)
32
+ @@delivery_notification_observers.delete(observer)
33
+ end
34
+
35
+ # Called when delivery is taking place
36
+ #
37
+ # @param [Sms::Message] sms
38
+ def inform_observers(sms)
39
+ @@delivery_notification_observers.each do |observer|
40
+ observer.delivered_sms(sms)
41
+ end
42
+ end
43
+
44
+ def deliver_sms(sms) #:nodoc:
45
+ ActiveSupport::Notifications.instrument("deliver.sms") do |payload|
46
+ set_payload_for_sms(payload, sms)
47
+ yield # Let Sms do the delivery actions
48
+ end
49
+ end
50
+
51
+ # Receive an SMS
52
+ #
53
+ # @param [Hash] params
54
+ # @option params [String] :from
55
+ # @option params [String] :to
56
+ # @option params [String] :text
57
+ def receive(params)
58
+ ActiveSupport::Notifications.instrument("receive.sms") do |payload|
59
+ sms = Sms::Message.new(params)
60
+ set_payload_for_sms(payload, sms)
61
+ new.receive(sms)
62
+ end
63
+ end
64
+
65
+ def set_payload_for_sms(payload, sms) #:nodoc:
66
+ payload[:from] = sms.from
67
+ payload[:to] = sms.to
68
+ payload[:text] = sms.text
69
+ end
70
+
71
+ end
72
+
73
+ class DeliveryError < StandardError
74
+ attr_reader :code
75
+ def initialize(msg, code = nil)
76
+ @code = code.to_i if code
77
+ super(msg)
78
+ end
79
+ end
80
+ end
81
+
82
+ require 'sms/message'
83
+ require 'sms/log_subscriber'
@@ -0,0 +1,21 @@
1
+ require 'securerandom'
2
+ require 'active_support/log_subscriber'
3
+ require 'active_support/notifications'
4
+
5
+ class Sms
6
+ class LogSubscriber < ActiveSupport::LogSubscriber
7
+ def deliver(event)
8
+ recipient = event.payload[:to]
9
+ info("Sent sms to #{recipient} (%1.fms)" % event.duration)
10
+ debug(event.payload[:text])
11
+ end
12
+
13
+ def receive(event)
14
+ sender = event.payload[:from]
15
+ info("Received sms from #{sender} (%1.fms)" % event.duration)
16
+ debug(event.payload[:text])
17
+ end
18
+ end
19
+ end
20
+
21
+ Sms::LogSubscriber.attach_to :sms
@@ -0,0 +1,63 @@
1
+ class Sms
2
+ class Message
3
+
4
+ # Default: true
5
+ attr_accessor :perform_deliveries
6
+
7
+ # Default: true
8
+ attr_accessor :raise_delivery_errors
9
+
10
+ # Default: Sms
11
+ # Should respond_to :deliver_sms
12
+ attr_accessor :delivery_handler
13
+
14
+ attr_reader :from, :to, :text
15
+ def initialize(args = {})
16
+ @delivery_handler = Sms
17
+ @perform_deliveries = true
18
+ @raise_delivery_errors = true
19
+ @from, @to, @text = args[:from], args[:to], args[:text]
20
+ end
21
+
22
+ # Hash representing the message
23
+ #
24
+ # @return [Hash] message
25
+ def serializable_hash
26
+ {to: to, text: text}.tap {|hash| hash[:from] = from if from}
27
+ end
28
+
29
+ # Perform the delivery of this message
30
+ #
31
+ # @return [Sms::Message] self
32
+ def deliver
33
+ #inform_interceptors
34
+ if delivery_handler
35
+ delivery_handler.deliver_sms(self) { do_delivery }
36
+ else
37
+ do_delivery
38
+ end
39
+ inform_observers
40
+ self
41
+ end
42
+
43
+ private
44
+ def do_delivery
45
+ begin
46
+ if perform_deliveries
47
+ delivery_method.deliver!(self)
48
+ end
49
+ rescue Exception => e
50
+ raise e if raise_delivery_errors
51
+ end
52
+ end
53
+
54
+ def delivery_method
55
+ Sms.delivery_method
56
+ end
57
+
58
+ def inform_observers
59
+ Sms.inform_observers(self)
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,49 @@
1
+ require 'net/https'
2
+
3
+ class Sms
4
+ module Method
5
+ class Bezeq
6
+ URL = URI.parse('https://vast.bezeq.co.il/imsc/interfaces/largeaccount/la3.sms')
7
+
8
+ # New instance of Bezeq delivery method
9
+ #
10
+ # @param [Hash] config
11
+ # @option config [String] :account
12
+ # @option config [String] :user
13
+ # @option config [String] :pass
14
+ # @option config [String] :from
15
+ # @option config [String] :port
16
+ def initialize(config)
17
+ @config = config.dup
18
+ end
19
+
20
+ # Send an MT message
21
+ # https://vast.bezeq.co.il/imsc/interfaces/largeaccount/la3.sms?account=myaccount&
22
+ # user=smsuser&pass=mypass&from=1234&to=972541234567&port=0&text=Hello+world
23
+ #
24
+ # @param [Sms::Message] sms
25
+ def deliver!(sms)
26
+ req = Net::HTTP::Post.new(URL.path)
27
+ hash = sms.serializable_hash
28
+ if hash[:to].is_a?(Array)
29
+ to = hash.delete(:to)
30
+ hash['to[]'] = to
31
+ end
32
+
33
+ req.form_data = @config.merge(hash)
34
+
35
+ res = Net::HTTP.start(URL.host, URL.port) do |http|
36
+ http.request(req)
37
+ end
38
+
39
+ case res
40
+ when Net::HTTPSuccess
41
+ true
42
+ else
43
+ raise DeliveryError.new(res.body, res.code)
44
+ end
45
+
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,16 @@
1
+ require 'csv'
2
+ class Sms
3
+ module Method
4
+ class File
5
+ def initialize
6
+ @file = ::File.open('/tmp/sms.csv', 'w')
7
+ @file.sync = true
8
+ @file.write("from,to,text\n")
9
+ end
10
+
11
+ def deliver!(sms)
12
+ @file.write([sms.from, sms.to, sms.text].to_csv)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,50 @@
1
+ require 'serialport'
2
+ require 'time'
3
+
4
+ class Sms
5
+ module Method
6
+ class GSM
7
+
8
+ def initialize(options = {})
9
+ raise ArgumentError.new('No :smsc was provided') unless options[:smsc]
10
+ @port = SerialPort.new(options[:port] || 3, options[:baud] || 38400, options[:bits] || 8, options[:stop] || 1, SerialPort::NONE)
11
+ @debug = options[:debug]
12
+ cmd("AT")
13
+ # Set to text mode
14
+ cmd("AT+CMGF=1")
15
+ # Set SMSC number
16
+ cmd(%Q{AT+CSCA="#{options[:smsc]}"})
17
+ end
18
+
19
+ def close
20
+ @port.close
21
+ end
22
+
23
+ private
24
+ def cmd(cmd)
25
+ @port.write(cmd + "\r")
26
+ wait
27
+ end
28
+
29
+ def wait
30
+ buffer = ''
31
+ while IO.select([@port], [], [], 0.25)
32
+ chr = @port.getc.chr
33
+ print chr if @debug
34
+ buffer += chr
35
+ end
36
+ buffer
37
+ end
38
+
39
+ def deliver!(sms)
40
+ cmd(%Q{AT+CMGS="#{sms.to}"})
41
+ cmd("#{sms.text[0..140]}#{26.chr}\r\r")
42
+ sleep 1
43
+ wait
44
+ cmd("AT")
45
+ end
46
+ end
47
+
48
+ Gsm = GSM
49
+ end
50
+ end
@@ -0,0 +1,12 @@
1
+ class Sms
2
+ module Method
3
+ class Kannel
4
+ def deliver!(sms)
5
+ args = {}
6
+ args[:from] = sms.from if sms.from
7
+ sms = ::Kannel::Sms.new(sms.to, sms.text, args)
8
+ sms.send!
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ require 'twilio-ruby'
3
+
4
+ class Sms
5
+ module Method
6
+ # POST /2010-04-01/Accounts/[AccountSid]/SMS/Messages.json with
7
+ # From, To, Body
8
+ class Twilio
9
+ def initialize(account_sid, auth_token, default_from = nil)
10
+ @account_sid = account_sid
11
+ @auth_token = auth_token
12
+ @from = default_from
13
+ end
14
+
15
+ # @param [Sms::Message] sms
16
+ def deliver!(sms)
17
+ from = sms.from || @from
18
+ client.account.messages.create(from: from, to: sms.to, body: sms.text)
19
+ end
20
+
21
+ private
22
+ # Set up a client to talk to the Twilio REST API
23
+ def client
24
+ @client ||= ::Twilio::REST::Client.new(@account_sid, @auth_token)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,45 @@
1
+ require 'sms'
2
+
3
+ describe Sms::Message do
4
+ it 'serializes with from' do
5
+ h = {from: '123', to: '234', text: 'test'}
6
+ msg = Sms::Message.new(h)
7
+ expect(msg.serializable_hash).to eq(h)
8
+ end
9
+
10
+ it 'serializes without from' do
11
+ h = {to: '234', text: 'test'}
12
+ msg = Sms::Message.new(h)
13
+ expect(msg.serializable_hash).to eq(h)
14
+ end
15
+
16
+ context 'Deliveries' do
17
+ let(:message) { Sms::Message.new(from: '123', to: '234', text: 'test') }
18
+
19
+ before do
20
+ delivery = double('delivery')
21
+ Sms.delivery_method = delivery
22
+ expect(delivery).to receive(:deliver!).with(message)
23
+ end
24
+
25
+ it 'delivers' do
26
+ message.deliver
27
+ end
28
+
29
+ it 'uses delivery handler' do
30
+ handler = double('handler')
31
+ message.delivery_handler = handler
32
+ expect(handler).to receive(:deliver_sms).with(message).and_yield
33
+ message.deliver
34
+ end
35
+
36
+ it 'notifies observers' do
37
+ observer = double('observer')
38
+ expect(observer).to receive(:delivered_sms).with(message)
39
+ Sms.register_observer(observer)
40
+ message.deliver
41
+ Sms.unregister_observer(observer)
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,53 @@
1
+ require 'sms'
2
+ require 'sms/method/bezeq'
3
+ require 'sms/method/file'
4
+ require 'webmock/rspec'
5
+
6
+ describe Sms::Method::Bezeq do
7
+ let(:url) { "http://vast.bezeq.co.il:443/imsc/interfaces/largeaccount/la3.sms" }
8
+ let(:delivery_method) { Sms::Method::Bezeq.new(account: 'a', user: 'u', pass: 'p', from: '222') }
9
+
10
+ let(:message) { Sms::Message.new(:to => '123', :text => 'test') }
11
+ let(:body) do
12
+ {"account"=>"a", "user"=>"u", "pass"=>"p", "from"=>"222", "to"=>"123", "text"=>"test" }
13
+ end
14
+
15
+ before do
16
+ Sms.delivery_method = delivery_method
17
+ end
18
+
19
+ context 'Multiple recipients' do
20
+ let(:message) { Sms::Message.new(:to => %w[num1 num2 num3], :text => 'test') }
21
+ let(:body) do
22
+ {"account"=>"a", "user"=>"u", "pass"=>"p", "from"=>"222", "to"=>%w[num1 num2 num3], "text"=>"test"}
23
+ end
24
+
25
+ it 'handles multiple recipients' do
26
+ stub_request(:post, url).
27
+ with(body: body, headers: {'Accept'=>'*/*', 'Content-Type'=>'application/x-www-form-urlencoded', 'User-Agent'=>'Ruby'}).
28
+ to_return(status: 200, body: "OK", headers: {})
29
+ message.deliver
30
+ end
31
+
32
+ end
33
+
34
+ it "issues POST" do
35
+ stub_request(:post, url).
36
+ with(body: body, headers: {'Accept'=>'*/*', 'Content-Type'=>'application/x-www-form-urlencoded', 'User-Agent'=>'Ruby'}).
37
+ to_return(status: 200, body: "OK", headers: {})
38
+ message.deliver
39
+ end
40
+
41
+ it 'handles errors' do
42
+ stub_request(:post, url).with(body: body).
43
+ to_return(status: 400, body: 'Malformed Request', headers: {})
44
+
45
+ expect {message.deliver}.to raise_error(Sms::DeliveryError)
46
+ begin
47
+ message.deliver
48
+ rescue Sms::DeliveryError => e
49
+ expect(e.code).to eq(400)
50
+ expect(e.message).to eq('Malformed Request')
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,52 @@
1
+ require 'sms'
2
+
3
+ describe Sms do
4
+ let(:hash) do
5
+ {from: '123', to: '234', text: 'test'}
6
+ end
7
+
8
+ let(:message) { Sms::Message.new(hash) }
9
+
10
+ context 'Delivering SMS' do
11
+
12
+ it 'notifies the listeners' do
13
+ listener = double('listener')
14
+ expect(listener).to receive(:call) do |*params|
15
+ expect(params.first).to eq('deliver.sms')
16
+ expect(params.last).to eq(hash)
17
+ end
18
+ subscriber = ActiveSupport::Notifications.subscribe('deliver.sms', listener)
19
+ Sms.deliver_sms(message) {}
20
+ ActiveSupport::Notifications.unsubscribe(subscriber)
21
+ end
22
+
23
+ end
24
+
25
+ context 'Receiving SMS' do
26
+
27
+ class Receiver < Sms
28
+ def receive(sms)
29
+ end
30
+ end
31
+
32
+ it 'receives messages' do
33
+ receiver = double('receiver').tap do |m|
34
+ expect(m).to receive(:receive) {|msg| expect(msg.serializable_hash).to eq(hash)}
35
+ end
36
+ expect(Receiver).to receive(:new).and_return(receiver)
37
+ Receiver.receive(hash)
38
+ end
39
+
40
+ it 'notifies the listeners' do
41
+ listener = double('listener')
42
+ expect(listener).to receive(:call) do |*params|
43
+ expect(params.first).to eq('receive.sms')
44
+ expect(params.last).to eq(hash)
45
+ end
46
+ subscriber = ActiveSupport::Notifications.subscribe('receive.sms', listener)
47
+ Receiver.receive(hash)
48
+ ActiveSupport::Notifications.unsubscribe(subscriber)
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,13 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'webmock/rspec'
5
+ require 'actionsms'
6
+
7
+ # Requires supporting files with custom matchers and macros, etc,
8
+ # in ./support/ and its subdirectories.
9
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
10
+
11
+ RSpec.configure do |config|
12
+
13
+ end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: actionsms
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Roman Shterenzon
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '3.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 3.2.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 3.2.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: rdoc
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: jeweler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Like ActionMailer, but for SMS
84
+ email: romanbsd@yahoo.com
85
+ executables: []
86
+ extensions: []
87
+ extra_rdoc_files:
88
+ - LICENSE.txt
89
+ - README.md
90
+ files:
91
+ - ".rspec"
92
+ - Gemfile
93
+ - Gemfile.lock
94
+ - LICENSE.txt
95
+ - README.md
96
+ - Rakefile
97
+ - VERSION
98
+ - actionsms.gemspec
99
+ - lib/actionsms.rb
100
+ - lib/sms.rb
101
+ - lib/sms/log_subscriber.rb
102
+ - lib/sms/message.rb
103
+ - lib/sms/method/bezeq.rb
104
+ - lib/sms/method/file.rb
105
+ - lib/sms/method/gsm.rb
106
+ - lib/sms/method/kannel.rb
107
+ - lib/sms/method/twilio.rb
108
+ - spec/sms/message_spec.rb
109
+ - spec/sms/method/bezeq_spec.rb
110
+ - spec/sms_spec.rb
111
+ - spec/spec_helper.rb
112
+ homepage: http://github.com/romanbsd/actionsms
113
+ licenses:
114
+ - MIT
115
+ metadata: {}
116
+ post_install_message:
117
+ rdoc_options: []
118
+ require_paths:
119
+ - lib
120
+ required_ruby_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ required_rubygems_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ requirements: []
131
+ rubyforge_project:
132
+ rubygems_version: 2.4.6
133
+ signing_key:
134
+ specification_version: 4
135
+ summary: Like ActionMailer, but for SMS
136
+ test_files: []