em-kannel 0.2.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.
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,53 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ em-kannel (0.2.0)
5
+ activemodel (~> 3.1)
6
+ em-http-request (>= 1.0.0.beta.4)
7
+ eventmachine (>= 1.0.0.beta.3)
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ activemodel (3.1.3)
13
+ activesupport (= 3.1.3)
14
+ builder (~> 3.0.0)
15
+ i18n (~> 0.6)
16
+ activesupport (3.1.3)
17
+ multi_json (~> 1.0)
18
+ addressable (2.2.6)
19
+ builder (3.0.0)
20
+ cookiejar (0.3.0)
21
+ crack (0.3.1)
22
+ diff-lcs (1.1.3)
23
+ em-http-request (1.0.1)
24
+ addressable (>= 2.2.3)
25
+ cookiejar
26
+ em-socksify
27
+ eventmachine (>= 1.0.0.beta.4)
28
+ http_parser.rb (>= 0.5.3)
29
+ em-socksify (0.1.0)
30
+ eventmachine
31
+ eventmachine (1.0.0.beta.4)
32
+ http_parser.rb (0.5.3)
33
+ i18n (0.6.0)
34
+ multi_json (1.0.4)
35
+ rspec (2.7.0)
36
+ rspec-core (~> 2.7.0)
37
+ rspec-expectations (~> 2.7.0)
38
+ rspec-mocks (~> 2.7.0)
39
+ rspec-core (2.7.0)
40
+ rspec-expectations (2.7.0)
41
+ diff-lcs (~> 1.1.2)
42
+ rspec-mocks (2.7.0)
43
+ webmock (1.7.7)
44
+ addressable (~> 2.2, > 2.2.5)
45
+ crack (>= 0.1.7)
46
+
47
+ PLATFORMS
48
+ ruby
49
+
50
+ DEPENDENCIES
51
+ em-kannel!
52
+ rspec (~> 2.7.0)
53
+ webmock (~> 1.7.7)
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ (The MIT-License)
2
+
3
+ Copyright (c) 2011 GroupMe
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # Kannel SMS delivery for EventMachine
2
+
3
+ # Install
4
+
5
+ gem "em-kannel", :git => "git://github.com/groupme/em-kannel.git"
6
+
7
+ # Usage
8
+
9
+ require "em-kannel"
10
+
11
+ kannel = EM::Kannel.new(
12
+ username: "user",
13
+ password: "password",
14
+ url: "http://www.example.com/sendsms"
15
+ )
16
+
17
+
18
+ EM.run do
19
+ kannel.sendsms(
20
+ from: "+12105551010",
21
+ to: "+12125551212 +17185551212",
22
+ body: "Hello World"
23
+ )
24
+ EM.stop
25
+ end
26
+
27
+ ## Callbacks
28
+
29
+ You can pass a block to process the response body:
30
+
31
+ kannel.sendsms(message_options) do |response|
32
+ if response.success?
33
+ log("Hooray!")
34
+ else
35
+ log("Boo! #{response.body}")
36
+ end
37
+ end
38
+
39
+ # Testing
40
+
41
+ To test em-kannel's deliveries, start by simply requiring this file after EM::Kannel has already
42
+ been loaded:
43
+
44
+ require "em-kannel"
45
+ require "em-kannel/test_helper"
46
+
47
+ This will nullify actual deliveries and instead, push them onto an accessible
48
+ list:
49
+
50
+ kannel = EM::Kannel.new(configuration_options)
51
+
52
+ expect {
53
+ kannel.send_sms(message_options)
54
+ }.to change { EM::Kannel.deliveries.size }.by(1)
55
+
56
+ message = EM::Kannel.deliveries.first
57
+ message.should be_an_instance_of(EM::Kannel::Message)
58
+ message.body.should == ...
59
+
60
+ # Legal
61
+
62
+ See LICENSE for details
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require "rspec/core/rake_task"
2
+
3
+ RSpec::Core::RakeTask.new(:spec)
4
+
5
+ task :default => :spec
data/em-kannel.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+
3
+ require "em-kannel/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "em-kannel"
7
+ s.version = EventMachine::Kannel::VERSION
8
+ s.authors = ["John Pignata"]
9
+ s.email = ["john@groupme.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{EventMachine-driven SMS delivery via Kannel}
12
+
13
+ s.rubyforge_project = "em-kannel"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_dependency "eventmachine", ">= 1.0.0.beta.3"
21
+ s.add_dependency "em-http-request", ">= 1.0.0.beta.4"
22
+ s.add_dependency "activemodel", "~> 3.1"
23
+
24
+ s.add_development_dependency "rspec", "~> 2.7.0"
25
+ s.add_development_dependency "webmock", "~> 1.7.7"
26
+ end
data/lib/em-kannel.rb ADDED
@@ -0,0 +1,39 @@
1
+ require "active_model"
2
+ require "active_support/core_ext/hash"
3
+ require "em-http-request"
4
+ require "logger"
5
+
6
+ require "em-kannel/validations"
7
+ require "em-kannel/configuration"
8
+ require "em-kannel/message"
9
+ require "em-kannel/log_message"
10
+ require "em-kannel/client"
11
+ require "em-kannel/response"
12
+
13
+ module EventMachine
14
+ class Kannel
15
+ attr_accessor :configuration
16
+
17
+ def initialize(configuration_options={})
18
+ self.configuration = Configuration.new(configuration_options)
19
+ end
20
+
21
+ def self.logger
22
+ @logger ||= Logger.new(STDOUT)
23
+ end
24
+
25
+ def self.logger=(new_logger)
26
+ @logger = new_logger
27
+ end
28
+
29
+ def send_sms(message_options, &block)
30
+ configuration.validate!
31
+
32
+ message = Message.new(message_options)
33
+ message.validate!
34
+
35
+ client = Client.new(message, configuration)
36
+ client.deliver(&block)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,39 @@
1
+ module EventMachine
2
+ class Kannel
3
+ class Client
4
+ attr_accessor :message, :configuration
5
+
6
+ def initialize(message, configuration)
7
+ self.message = message
8
+ self.configuration = configuration
9
+ end
10
+
11
+ def deliver(&block)
12
+ start = Time.now.to_f
13
+ http = EM::HttpRequest.new(configuration.url, options).get(query: query)
14
+
15
+ http.callback { callback(http, start, message, &block) }
16
+ http.errback { callback(http, start, message, &block) }
17
+ end
18
+
19
+ private
20
+
21
+ def options
22
+ { ssl: { verify_peer: configuration.verify_ssl_peer } }
23
+ end
24
+
25
+ def query
26
+ query = {}
27
+ query.merge!(configuration.as_query)
28
+ query.merge!(message.as_query)
29
+ end
30
+
31
+ def callback(http, start, message, &block)
32
+ response = Response.new(http, start)
33
+
34
+ LogMessage.new(message, response).log
35
+ block.call(response) if block_given?
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,39 @@
1
+ module EventMachine
2
+ class Kannel
3
+ class Configuration
4
+ include Validations
5
+
6
+ attr_accessor :username,
7
+ :password,
8
+ :url,
9
+ :dlr_callback_url,
10
+ :dlr_mask,
11
+ :verify_ssl_peer,
12
+ :smsc
13
+
14
+ validates :username, presence: true
15
+ validates :password, presence: true
16
+ validates :url, presence: true
17
+
18
+ def initialize(attributes={})
19
+ attributes = attributes.with_indifferent_access
20
+
21
+ self.username = attributes[:username]
22
+ self.password = attributes[:password]
23
+ self.url = attributes[:url]
24
+ self.dlr_callback_url = attributes[:dlr_callback_url]
25
+ self.dlr_mask = attributes[:dlr_mask]
26
+ self.verify_ssl_peer = attributes[:verify_ssl_peer]
27
+ self.smsc = attributes[:smsc]
28
+ end
29
+
30
+ def as_query
31
+ query = { username: username, password: password }
32
+ query[:"dlr-mask"] = dlr_mask if dlr_mask
33
+ query[:"dlr-url"] = dlr_callback_url if dlr_callback_url
34
+ query[:smsc] = smsc if smsc
35
+ query
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,30 @@
1
+ module EventMachine
2
+ class Kannel
3
+ class LogMessage
4
+ def initialize(message, response)
5
+ @message, @response = message, response
6
+ end
7
+
8
+ def log
9
+ EM::Kannel.logger.info(message)
10
+ end
11
+
12
+ private
13
+
14
+ def message
15
+ parts = [
16
+ "CODE=#{@response.status}",
17
+ "FROM=#{@message.from}",
18
+ "TO=#{@message.to}",
19
+ "BODY=#{@message.body[0..100]}",
20
+ "RESPONSE=#{@response.body}",
21
+ "TIME=#{@response.duration}"
22
+ ]
23
+ parts << "ERROR=#{@response.error}" unless @response.success?
24
+
25
+ parts.join(" ")
26
+ end
27
+ end
28
+ end
29
+ end
30
+
@@ -0,0 +1,25 @@
1
+ module EventMachine
2
+ class Kannel
3
+ class Message
4
+ include Validations
5
+
6
+ attr_accessor :body, :from, :to
7
+
8
+ validates :body, presence: true, length: { maximum: 160 }
9
+ validates :from, presence: true
10
+ validates :to, presence: true
11
+
12
+ def initialize(attributes={})
13
+ attributes = attributes.with_indifferent_access
14
+
15
+ self.from = attributes[:from]
16
+ self.to = attributes[:to]
17
+ self.body = attributes[:body]
18
+ end
19
+
20
+ def as_query
21
+ { from: from, to: to, text: body }
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,38 @@
1
+ module EventMachine
2
+ class Kannel
3
+ class Response
4
+ attr_reader :duration
5
+
6
+ def initialize(http, start=nil)
7
+ @http = http
8
+ @duration = compute_duration(start)
9
+ end
10
+
11
+ def status
12
+ @http.response_header.status.to_i
13
+ end
14
+
15
+ def success?
16
+ status == 202
17
+ end
18
+
19
+ def body
20
+ @http.response
21
+ end
22
+
23
+ def error
24
+ @http.error
25
+ end
26
+
27
+ def guid
28
+ body.split(": ").last
29
+ end
30
+
31
+ private
32
+
33
+ def compute_duration(start)
34
+ start && ((Time.now.to_f - start.to_f) * 1000.0).round
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,28 @@
1
+ require "ostruct"
2
+
3
+ module EventMachine
4
+ class Kannel
5
+ def self.deliveries
6
+ @deliveries ||= []
7
+ end
8
+
9
+ Client.class_eval do
10
+ def fake_response
11
+ guid = UUID.new.generate
12
+
13
+ status = OpenStruct.new(status: 202)
14
+ http = OpenStruct.new(
15
+ response_header: status,
16
+ response: "0: Accepted for delivery: #{guid}"
17
+ )
18
+
19
+ Response.new(http, Time.now)
20
+ end
21
+
22
+ def deliver(&block)
23
+ EM::Kannel.deliveries << @message
24
+ yield(fake_response) if block_given?
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,30 @@
1
+ module EventMachine
2
+ class Kannel
3
+ module Validations
4
+ def self.included(base)
5
+ base.class_eval do
6
+ include ActiveModel::Validations
7
+ end
8
+ end
9
+
10
+ def validate!
11
+ if invalid?
12
+ message = "Invalid #{friendly_name}: #{full_messages}"
13
+ raise ArgumentError.new(message)
14
+ end
15
+
16
+ true
17
+ end
18
+
19
+ def friendly_name
20
+ self.class.model_name.human
21
+ end
22
+
23
+ private
24
+
25
+ def full_messages
26
+ errors.full_messages.to_sentence
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,5 @@
1
+ module EventMachine
2
+ class Kannel
3
+ VERSION = "0.2.0"
4
+ end
5
+ end
@@ -0,0 +1,85 @@
1
+ require "spec_helper"
2
+
3
+ describe EventMachine::Kannel::Client do
4
+ describe "#deliver" do
5
+ let(:configuration) {
6
+ EM::Kannel::Configuration.new(
7
+ url: "http://www.example.com/api",
8
+ username: "user",
9
+ password: "pass"
10
+ )
11
+ }
12
+
13
+ let(:message) do
14
+ EM::Kannel::Message.new(
15
+ from: "+12125551212",
16
+ to: "+17185551212",
17
+ body: "testing"
18
+ )
19
+ end
20
+
21
+ it "delivers the message to the specified URL" do
22
+ stub = stub_request(:get, "http://www.example.com/api").with(
23
+ query: {
24
+ username: "user",
25
+ password: "pass",
26
+ from: "+12125551212",
27
+ to: "+17185551212",
28
+ text: "testing"
29
+ }
30
+ )
31
+
32
+ EM.run_block {
33
+ EM::Kannel::Client.new(message, configuration).deliver
34
+ }
35
+
36
+ stub.should have_been_requested
37
+ end
38
+
39
+ context "delivery succeeds" do
40
+ it "logs the delivery" do
41
+ uuid = "24b8d670-0ad6-012f-13e0-60c5470504ea"
42
+
43
+ stub = stub_request(:get, "http://www.example.com/api").with(
44
+ query: {
45
+ username: "user",
46
+ password: "pass",
47
+ from: "+12125551212",
48
+ to: "+17185551212",
49
+ text: "testing"
50
+ }).
51
+ to_return(:status => 202, :body => uuid)
52
+
53
+ EM::Kannel.logger.should_receive(:info).with(
54
+ /CODE=202 FROM=\+12125551212 TO=\+17185551212 BODY=testing RESPONSE=#{uuid} TIME=[0-9]/
55
+ )
56
+
57
+ EM.run_block {
58
+ EM::Kannel::Client.new(message, configuration).deliver
59
+ }
60
+ end
61
+ end
62
+
63
+ context "delivery fails" do
64
+ it "logs the failure" do
65
+ stub = stub_request(:get, "http://www.example.com/api").with(
66
+ query: {
67
+ username: "user",
68
+ password: "pass",
69
+ from: "+12125551212",
70
+ to: "+17185551212",
71
+ text: "testing"
72
+ }).
73
+ to_return(:status => 404, :body => "API not available")
74
+
75
+ EM::Kannel.logger.should_receive(:info).with(
76
+ /CODE=404 FROM=\+12125551212 TO=\+17185551212 BODY=testing RESPONSE=API not available TIME=[0-9]/
77
+ )
78
+
79
+ EM.run_block {
80
+ EM::Kannel::Client.new(message, configuration).deliver
81
+ }
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,58 @@
1
+ require "spec_helper"
2
+
3
+ describe EventMachine::Kannel::Configuration do
4
+ let(:attributes) do
5
+ {
6
+ :username => "user",
7
+ :password => "pass",
8
+ :url => "http://www.example.com/url",
9
+ :dlr_callback_url => "http://www.example.com/dlr_callback_url",
10
+ :dlr_mask => 1,
11
+ :smsc => "Provider"
12
+ }
13
+ end
14
+
15
+ describe ".new" do
16
+ it "sets the attributes passed in the argument hash" do
17
+ configuration = EM::Kannel::Configuration.new(attributes)
18
+
19
+ attributes.each do |attribute_name, attribute_value|
20
+ configuration.send(attribute_name).should == attribute_value
21
+ end
22
+ end
23
+ end
24
+
25
+ describe "validations" do
26
+ let(:configuration) do
27
+ EM::Kannel::Configuration.new(
28
+ :username => "user",
29
+ :password => "pass"
30
+ )
31
+ end
32
+
33
+ it "validates presence of username" do
34
+ configuration.username = nil
35
+ configuration.should_not be_valid
36
+ configuration.errors[:username].should include("can't be blank")
37
+ end
38
+
39
+ it "validates presence of password" do
40
+ configuration.password = nil
41
+ configuration.should_not be_valid
42
+ configuration.errors[:password].should include("can't be blank")
43
+ end
44
+ end
45
+
46
+ describe "#as_query" do
47
+ it "returns a hash for use in the HTTP request" do
48
+ configuration = EM::Kannel::Configuration.new(attributes)
49
+ configuration.as_query.should == {
50
+ :username => "user",
51
+ :password => "pass",
52
+ :"dlr-mask" => 1,
53
+ :"dlr-url" => "http://www.example.com/dlr_callback_url",
54
+ :smsc => "Provider"
55
+ }
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,53 @@
1
+ require "spec_helper"
2
+
3
+ describe EventMachine::Kannel::Message do
4
+ let(:message) {
5
+ EM::Kannel::Message.new.tap do |message|
6
+ message.body = "hi there"
7
+ message.from = "+12125551212"
8
+ message.to = ["+17185551212"]
9
+ end
10
+ }
11
+
12
+ describe "validations" do
13
+ context "with valid attributes" do
14
+ it "is valid" do
15
+ message.should be_valid
16
+ end
17
+ end
18
+
19
+ it "validates presence of body" do
20
+ message.body = nil
21
+ message.should_not be_valid
22
+ message.errors[:body].should include("can't be blank")
23
+ end
24
+
25
+ it "validates body length is at most 160 characters" do
26
+ message.body = "x" * 161
27
+ message.should_not be_valid
28
+ message.errors[:body].should include("is too long (maximum is 160 characters)")
29
+ end
30
+
31
+ it "validates presence of from" do
32
+ message.from = nil
33
+ message.should_not be_valid
34
+ message.errors[:from].should include("can't be blank")
35
+ end
36
+
37
+ it "validates presence of to" do
38
+ message.to = nil
39
+ message.should_not be_valid
40
+ message.errors[:to].should include("can't be blank")
41
+ end
42
+ end
43
+
44
+ describe "#as_query" do
45
+ it "returns a hash for use in the HTTP request" do
46
+ message.as_query.should == {
47
+ from: "+12125551212",
48
+ to: ["+17185551212"],
49
+ text: "hi there"
50
+ }
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,54 @@
1
+ require "spec_helper"
2
+
3
+ describe EM::Kannel::Response do
4
+ let(:header) { mock(:header, status: "202") }
5
+ let(:body) { "0: Accepted for delivery: 26ecfeea-6015-4025-bcae-0d0b71467d83" }
6
+ let(:http) { mock(:http_client, response_header: header, response: body) }
7
+
8
+ before do
9
+ now = Time.now
10
+ Time.stub(:now).and_return(now)
11
+ end
12
+
13
+ describe "#status" do
14
+ it "returns the status code" do
15
+ started = Time.now - 10
16
+ http = mock(:http_client, response_header: header)
17
+
18
+ response = EM::Kannel::Response.new(http, started)
19
+ response.status.should == 202
20
+ end
21
+ end
22
+
23
+ describe "#success?" do
24
+ context "the status code is 202" do
25
+ it "returns true" do
26
+ response = EM::Kannel::Response.new(http)
27
+ response.should be_success
28
+ end
29
+ end
30
+
31
+ context "other status codes" do
32
+ let(:header) { mock(:header, status: "500") }
33
+
34
+ it "returns false" do
35
+ response = EM::Kannel::Response.new(http)
36
+ response.should_not be_success
37
+ end
38
+ end
39
+ end
40
+
41
+ describe "#body" do
42
+ it "returns the body of the response" do
43
+ response = EM::Kannel::Response.new(http)
44
+ response.body.should == body
45
+ end
46
+ end
47
+
48
+ describe "#guid" do
49
+ it "returns the guid of the response" do
50
+ response = EM::Kannel::Response.new(http)
51
+ response.guid.should == "26ecfeea-6015-4025-bcae-0d0b71467d83"
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,30 @@
1
+ require "spec_helper"
2
+
3
+ describe EM::Kannel::Validations do
4
+ before do
5
+ class Model
6
+ include EM::Kannel::Validations
7
+ attr_accessor :value
8
+ validates :value, presence: true
9
+ end
10
+ end
11
+
12
+ describe "#validate!" do
13
+ context "invalid" do
14
+ it "raises an ArgumentError" do
15
+ expect {
16
+ Model.new.validate!
17
+ }.to raise_exception(ArgumentError, /Invalid Model/)
18
+ end
19
+ end
20
+
21
+ context "valid" do
22
+ it "returns true" do
23
+ instance = Model.new
24
+ instance.value = "value"
25
+ instance.validate!.should be_true
26
+ end
27
+ end
28
+ end
29
+
30
+ end
@@ -0,0 +1,14 @@
1
+ require "spec_helper"
2
+
3
+ describe EventMachine::Kannel do
4
+ describe ".send_sms" do
5
+ context "invalid configuration options" do
6
+ it "raises an ArgumentError with the validation errors" do
7
+ expect {
8
+ kannel = EM::Kannel.new({})
9
+ kannel.send_sms({})
10
+ }.to raise_exception(ArgumentError, /Invalid Configuration/)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,8 @@
1
+ require "em-kannel"
2
+ require 'webmock/rspec'
3
+
4
+ RSpec.configure do |config|
5
+ config.before(:each) do
6
+ EM::Kannel.logger = Logger.new("/dev/null")
7
+ end
8
+ end
metadata ADDED
@@ -0,0 +1,148 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: em-kannel
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - John Pignata
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-04-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: eventmachine
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.0.0.beta.3
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.0.0.beta.3
30
+ - !ruby/object:Gem::Dependency
31
+ name: em-http-request
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 1.0.0.beta.4
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 1.0.0.beta.4
46
+ - !ruby/object:Gem::Dependency
47
+ name: activemodel
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '3.1'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '3.1'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rspec
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 2.7.0
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 2.7.0
78
+ - !ruby/object:Gem::Dependency
79
+ name: webmock
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: 1.7.7
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: 1.7.7
94
+ description:
95
+ email:
96
+ - john@groupme.com
97
+ executables: []
98
+ extensions: []
99
+ extra_rdoc_files: []
100
+ files:
101
+ - .rspec
102
+ - Gemfile
103
+ - Gemfile.lock
104
+ - LICENSE
105
+ - README.md
106
+ - Rakefile
107
+ - em-kannel.gemspec
108
+ - lib/em-kannel.rb
109
+ - lib/em-kannel/client.rb
110
+ - lib/em-kannel/configuration.rb
111
+ - lib/em-kannel/log_message.rb
112
+ - lib/em-kannel/message.rb
113
+ - lib/em-kannel/response.rb
114
+ - lib/em-kannel/test_helper.rb
115
+ - lib/em-kannel/validations.rb
116
+ - lib/em-kannel/version.rb
117
+ - spec/em-kannel/client_spec.rb
118
+ - spec/em-kannel/configuration_spec.rb
119
+ - spec/em-kannel/message_spec.rb
120
+ - spec/em-kannel/response_spec.rb
121
+ - spec/em-kannel/validations_spec.rb
122
+ - spec/em-kannel_spec.rb
123
+ - spec/spec_helper.rb
124
+ homepage: ''
125
+ licenses: []
126
+ post_install_message:
127
+ rdoc_options: []
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ none: false
132
+ requirements:
133
+ - - ! '>='
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ required_rubygems_version: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ requirements: []
143
+ rubyforge_project: em-kannel
144
+ rubygems_version: 1.8.19
145
+ signing_key:
146
+ specification_version: 3
147
+ summary: EventMachine-driven SMS delivery via Kannel
148
+ test_files: []