em-kannel 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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: []