moonshado-sms 0.3.1 → 0.4.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/Rakefile +6 -6
- data/VERSION.yml +2 -2
- data/lib/moonshado-sms.rb +10 -7
- data/lib/moonshado/configuration.rb +82 -0
- data/lib/moonshado/keywords.rb +39 -30
- data/lib/moonshado/sender.rb +46 -0
- data/lib/moonshado/sms.rb +44 -24
- data/moonshado-sms.gemspec +68 -0
- metadata +42 -24
data/Rakefile
CHANGED
@@ -9,10 +9,10 @@ begin
|
|
9
9
|
gem.email = "tech@moonshado.com"
|
10
10
|
gem.homepage = "http://github.com/moonshado/moonshado-sms"
|
11
11
|
gem.authors = ["Kevin Patel"]
|
12
|
-
gem.add_development_dependency "
|
13
|
-
gem.
|
14
|
-
gem.add_runtime_dependency "
|
15
|
-
gem.add_runtime_dependency "
|
12
|
+
gem.add_development_dependency "shoulda", ">= 0"
|
13
|
+
gem.add_development_dependency "webmock", ">= 0"
|
14
|
+
gem.add_runtime_dependency "rest-client", '1.5.1'
|
15
|
+
gem.add_runtime_dependency "yajl-ruby", '0.7.6'
|
16
16
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
17
17
|
end
|
18
18
|
Jeweler::GemcutterTasks.new
|
@@ -23,7 +23,7 @@ end
|
|
23
23
|
require 'rake/testtask'
|
24
24
|
Rake::TestTask.new(:test) do |test|
|
25
25
|
test.libs << 'lib' << 'test'
|
26
|
-
test.pattern = 'test
|
26
|
+
test.pattern = 'test/**/*_test.rb'
|
27
27
|
test.verbose = true
|
28
28
|
end
|
29
29
|
|
@@ -31,7 +31,7 @@ begin
|
|
31
31
|
require 'rcov/rcovtask'
|
32
32
|
Rcov::RcovTask.new do |test|
|
33
33
|
test.libs << 'test'
|
34
|
-
test.pattern = 'test
|
34
|
+
test.pattern = 'test/**/*_test.rb'
|
35
35
|
test.verbose = true
|
36
36
|
end
|
37
37
|
rescue LoadError
|
data/VERSION.yml
CHANGED
data/lib/moonshado-sms.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
-
|
1
|
+
require 'rubygems'
|
2
|
+
require 'restclient'
|
3
|
+
require 'yajl'
|
4
|
+
require 'moonshado/configuration'
|
5
|
+
require 'moonshado/sms'
|
6
|
+
require 'moonshado/keywords'
|
7
|
+
require 'moonshado/sender'
|
2
8
|
|
3
|
-
module Moonshado
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
require 'sms'
|
8
|
-
require 'keywords'
|
9
|
+
module Moonshado
|
10
|
+
|
11
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Moonshado
|
2
|
+
class Configuration
|
3
|
+
|
4
|
+
OPTIONS = [:api_key, :development_environments, :keywords,
|
5
|
+
:sms_uri, :keyword_uri, :auto_register_keyword,
|
6
|
+
:environment_name, :host, :http_open_timeout,
|
7
|
+
:http_read_timeout, :port, :protocol, :secure].freeze
|
8
|
+
|
9
|
+
attr_accessor :api_key
|
10
|
+
attr_accessor :keywords
|
11
|
+
attr_accessor :sms_uri
|
12
|
+
attr_accessor :keywords_uri
|
13
|
+
attr_accessor :secure
|
14
|
+
attr_accessor :http_open_timeout
|
15
|
+
attr_accessor :http_read_timeout
|
16
|
+
attr_accessor :host
|
17
|
+
attr_accessor :auto_register_keywords
|
18
|
+
attr_accessor :production_environment
|
19
|
+
|
20
|
+
alias_method :secure?, :secure
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
@secure = false
|
24
|
+
@host = 'heroku.moonshado.com'
|
25
|
+
@http_open_timeout = 2
|
26
|
+
@http_read_timeout = 5
|
27
|
+
@production_environment = true
|
28
|
+
@sms_uri = '/sms'
|
29
|
+
@keywords_uri = '/keywords'
|
30
|
+
@auto_register_keywords = false
|
31
|
+
end
|
32
|
+
|
33
|
+
def api_key
|
34
|
+
formatted_api_key if @production_environment
|
35
|
+
end
|
36
|
+
|
37
|
+
def formatted_api_key
|
38
|
+
url_obj = URI.parse(@api_key)
|
39
|
+
|
40
|
+
if (url_obj.class == URI::Generic)
|
41
|
+
@api_key
|
42
|
+
else
|
43
|
+
url_obj.user
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def [](option)
|
48
|
+
send(option)
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_hash
|
52
|
+
OPTIONS.inject({}) do |hash, option|
|
53
|
+
hash.merge(option.to_sym => send(option))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def merge(hash)
|
58
|
+
to_hash.merge(hash)
|
59
|
+
end
|
60
|
+
|
61
|
+
def port
|
62
|
+
@port || default_port
|
63
|
+
end
|
64
|
+
|
65
|
+
def protocol
|
66
|
+
if secure?
|
67
|
+
'https'
|
68
|
+
else
|
69
|
+
'http'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
def default_port
|
75
|
+
if secure?
|
76
|
+
443
|
77
|
+
else
|
78
|
+
80
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/moonshado/keywords.rb
CHANGED
@@ -1,39 +1,48 @@
|
|
1
|
-
require 'active_support'
|
2
|
-
require 'rest_client'
|
3
|
-
require 'json'
|
4
|
-
|
5
1
|
module Moonshado
|
6
|
-
class
|
7
|
-
|
8
|
-
|
9
|
-
|
2
|
+
class Sms
|
3
|
+
class Keywords
|
4
|
+
class << self
|
5
|
+
def list
|
6
|
+
response = sender.get(configuration.keywords_uri)
|
10
7
|
|
11
|
-
|
12
|
-
|
13
|
-
"#{@url.scheme}://#{@url.user}:#{@url.password}@#{@url.host}:#{@url.port}/keywords"
|
14
|
-
end
|
8
|
+
parse(response.body)
|
9
|
+
end
|
15
10
|
|
16
|
-
|
17
|
-
|
11
|
+
def register_keywords
|
12
|
+
raise MoonshadoSMSException.new("no keywords specified") unless valid_keywords?
|
13
|
+
response = sender.send_to_moonshado({:keywords => configuration.keywords}, configuration.keywords_uri)
|
18
14
|
|
19
|
-
|
20
|
-
|
15
|
+
parse(response.body)
|
16
|
+
end
|
21
17
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
18
|
+
# def self.destory(keyword)
|
19
|
+
# response = RestClient.delete("#{url}/#{keyword}")
|
20
|
+
# parse(response.body)
|
21
|
+
# end
|
22
|
+
|
23
|
+
def valid_keywords?
|
24
|
+
configuration.keywords.is_a?(Hash) && (!configuration.keywords.empty?)
|
27
25
|
end
|
28
|
-
rescue Exception => e
|
29
|
-
puts "** Moonshado-Sms: error registering keywords"
|
30
|
-
end
|
31
|
-
end
|
32
26
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
27
|
+
class MoonshadoSMSException < StandardError; end
|
28
|
+
|
29
|
+
private
|
30
|
+
def sender
|
31
|
+
Moonshado::Sms.sender
|
32
|
+
end
|
33
|
+
|
34
|
+
def configuration
|
35
|
+
Moonshado::Sms.configuration
|
36
|
+
end
|
37
37
|
|
38
|
+
def production_environment?
|
39
|
+
configuration.production_environment
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse(json)
|
43
|
+
parser = Yajl::Parser.new.parse(json)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
38
47
|
end
|
39
|
-
end
|
48
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Moonshado
|
2
|
+
class Sender
|
3
|
+
attr_reader :host, :port, :secure, :http_open_timeout, :http_read_timeout, :protocol, :api_key
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
[:protocol, :host, :port, :secure, :http_open_timeout, :http_read_timeout, :api_key].each do |option|
|
7
|
+
instance_variable_set("@#{option}", options[option])
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def send_to_moonshado(data, uri)
|
12
|
+
http = RestClient::Resource.new(
|
13
|
+
url(uri),
|
14
|
+
:user => api_key,
|
15
|
+
:timeout => http_read_timeout,
|
16
|
+
:open_timeout => http_open_timeout
|
17
|
+
)
|
18
|
+
|
19
|
+
response = http.post(data)
|
20
|
+
end
|
21
|
+
|
22
|
+
def get(uri)
|
23
|
+
http = RestClient::Resource.new(
|
24
|
+
url(uri),
|
25
|
+
:user => api_key,
|
26
|
+
:timeout => http_read_timeout,
|
27
|
+
:open_timeout => http_open_timeout
|
28
|
+
)
|
29
|
+
|
30
|
+
response = http.get
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def url(uri = "")
|
35
|
+
URI.parse("#{protocol}://#{host}:#{port}").merge(uri).to_s
|
36
|
+
end
|
37
|
+
|
38
|
+
def configuration
|
39
|
+
Moonshado::Sms.configuration
|
40
|
+
end
|
41
|
+
|
42
|
+
def production_environment?
|
43
|
+
configuration.production_environment
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/moonshado/sms.rb
CHANGED
@@ -1,23 +1,18 @@
|
|
1
|
-
require 'active_support'
|
2
|
-
require 'rest_client'
|
3
|
-
require 'json'
|
4
|
-
|
5
1
|
module Moonshado
|
6
2
|
class Sms
|
7
|
-
cattr_accessor :config
|
8
3
|
attr_accessor :number, :message
|
9
4
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
5
|
+
class << self
|
6
|
+
attr_accessor :configuration
|
7
|
+
attr_accessor :sender
|
14
8
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
9
|
+
def configure
|
10
|
+
self.configuration ||= Configuration.new
|
11
|
+
yield(configuration)
|
12
|
+
self.sender = Sender.new(configuration)
|
13
|
+
if configuration.auto_register_keywords
|
14
|
+
Moonshado::Sms::Keywords.register_keywords
|
15
|
+
end
|
21
16
|
end
|
22
17
|
end
|
23
18
|
|
@@ -26,25 +21,33 @@ module Moonshado
|
|
26
21
|
@message = message
|
27
22
|
end
|
28
23
|
|
24
|
+
# def self.find(id)
|
25
|
+
# if config[:test_env] == true
|
26
|
+
# {:sms => {:id => id, :reports => '[{"update_date":"2010-01-03T22:56:45-08:00","status_info":"test"}]'}, :stat => "ok"}
|
27
|
+
# else
|
28
|
+
# response = RestClient.get("#{url}/#{id}")
|
29
|
+
# JSON.parse(response.body)
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
|
29
33
|
def deliver_sms
|
30
34
|
raise MoonshadoSMSException.new("Invalid message") unless is_message_valid?(@message)
|
31
35
|
|
32
|
-
|
33
|
-
{:stat => 'ok', :id => Digest::SHA1.hexdigest(Time.now.to_s + rand(12341234).to_s)[1..16]}
|
34
|
-
else
|
35
|
-
response = RestClient.post(
|
36
|
-
Moonshado::Sms.url,
|
37
|
-
{:sms => {:device_address => format_number(@number), :message => @message}}
|
38
|
-
)
|
36
|
+
data = {:sms => {:device_address => format_number(@number), :message => @message}}
|
39
37
|
|
40
|
-
|
38
|
+
if production_environment?
|
39
|
+
response = sender.send_to_moonshado(data, configuration.sms_uri)
|
40
|
+
else
|
41
|
+
response = RestClient::Response.create('{"stat":"ok","id":"sms_id_mock"}', "", {})
|
41
42
|
end
|
43
|
+
|
44
|
+
parse(response.to_s)
|
42
45
|
rescue MoonshadoSMSException => exception
|
43
46
|
raise exception
|
44
47
|
end
|
45
48
|
|
46
49
|
def format_number(number)
|
47
|
-
formatted = number.
|
50
|
+
formatted = number.scan(/\d+/i).join
|
48
51
|
return is_number_valid?(formatted) ? formatted : (raise MoonshadoSMSException.new("Phone number (#{number}) is not formatted correctly"))
|
49
52
|
end
|
50
53
|
|
@@ -57,5 +60,22 @@ module Moonshado
|
|
57
60
|
end
|
58
61
|
|
59
62
|
class MoonshadoSMSException < StandardError; end
|
63
|
+
|
64
|
+
private
|
65
|
+
def sender
|
66
|
+
Moonshado::Sms.sender
|
67
|
+
end
|
68
|
+
|
69
|
+
def configuration
|
70
|
+
Moonshado::Sms.configuration
|
71
|
+
end
|
72
|
+
|
73
|
+
def production_environment?
|
74
|
+
configuration.production_environment
|
75
|
+
end
|
76
|
+
|
77
|
+
def parse(json)
|
78
|
+
parser = Yajl::Parser.new.parse(json)
|
79
|
+
end
|
60
80
|
end
|
61
81
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{moonshado-sms}
|
8
|
+
s.version = "0.4.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Kevin Patel"]
|
12
|
+
s.date = %q{2010-06-10}
|
13
|
+
s.email = %q{tech@moonshado.com}
|
14
|
+
s.extra_rdoc_files = [
|
15
|
+
"LICENSE",
|
16
|
+
"README.rdoc"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".document",
|
20
|
+
".gitignore",
|
21
|
+
"LICENSE",
|
22
|
+
"README.rdoc",
|
23
|
+
"Rakefile",
|
24
|
+
"VERSION.yml",
|
25
|
+
"gems/moonshado-sms-0.0.1/.gitignore",
|
26
|
+
"lib/moonshado-sms.rb",
|
27
|
+
"lib/moonshado/configuration.rb",
|
28
|
+
"lib/moonshado/keywords.rb",
|
29
|
+
"lib/moonshado/sender.rb",
|
30
|
+
"lib/moonshado/sms.rb",
|
31
|
+
"moonshado-sms.gemspec",
|
32
|
+
"test/helper.rb"
|
33
|
+
]
|
34
|
+
s.homepage = %q{http://github.com/moonshado/moonshado-sms}
|
35
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
36
|
+
s.require_paths = ["lib"]
|
37
|
+
s.rubygems_version = %q{1.3.7}
|
38
|
+
s.summary = %q{Moonshado SMS gem}
|
39
|
+
s.test_files = [
|
40
|
+
"test/configuration_test.rb",
|
41
|
+
"test/helper.rb",
|
42
|
+
"test/keywords_test.rb",
|
43
|
+
"test/sms_test.rb"
|
44
|
+
]
|
45
|
+
|
46
|
+
if s.respond_to? :specification_version then
|
47
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
48
|
+
s.specification_version = 3
|
49
|
+
|
50
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
51
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
52
|
+
s.add_development_dependency(%q<webmock>, [">= 0"])
|
53
|
+
s.add_runtime_dependency(%q<rest-client>, ["= 1.5.1"])
|
54
|
+
s.add_runtime_dependency(%q<yajl-ruby>, ["= 0.7.6"])
|
55
|
+
else
|
56
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
57
|
+
s.add_dependency(%q<webmock>, [">= 0"])
|
58
|
+
s.add_dependency(%q<rest-client>, ["= 1.5.1"])
|
59
|
+
s.add_dependency(%q<yajl-ruby>, ["= 0.7.6"])
|
60
|
+
end
|
61
|
+
else
|
62
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
63
|
+
s.add_dependency(%q<webmock>, [">= 0"])
|
64
|
+
s.add_dependency(%q<rest-client>, ["= 1.5.1"])
|
65
|
+
s.add_dependency(%q<yajl-ruby>, ["= 0.7.6"])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: moonshado-sms
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 15
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
8
|
+
- 4
|
9
|
+
- 0
|
10
|
+
version: 0.4.0
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Kevin Patel
|
@@ -14,61 +15,67 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2010-
|
18
|
+
date: 2010-06-10 00:00:00 -04:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
|
-
name:
|
22
|
+
name: shoulda
|
22
23
|
prerelease: false
|
23
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
24
26
|
requirements:
|
25
27
|
- - ">="
|
26
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
27
30
|
segments:
|
28
31
|
- 0
|
29
32
|
version: "0"
|
30
33
|
type: :development
|
31
34
|
version_requirements: *id001
|
32
35
|
- !ruby/object:Gem::Dependency
|
33
|
-
name:
|
36
|
+
name: webmock
|
34
37
|
prerelease: false
|
35
38
|
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
36
40
|
requirements:
|
37
|
-
- - "
|
41
|
+
- - ">="
|
38
42
|
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
39
44
|
segments:
|
40
|
-
-
|
41
|
-
|
42
|
-
|
43
|
-
version: 1.4.2
|
44
|
-
type: :runtime
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :development
|
45
48
|
version_requirements: *id002
|
46
49
|
- !ruby/object:Gem::Dependency
|
47
|
-
name:
|
50
|
+
name: rest-client
|
48
51
|
prerelease: false
|
49
52
|
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
50
54
|
requirements:
|
51
55
|
- - "="
|
52
56
|
- !ruby/object:Gem::Version
|
57
|
+
hash: 1
|
53
58
|
segments:
|
54
59
|
- 1
|
55
|
-
-
|
56
|
-
-
|
57
|
-
version: 1.
|
60
|
+
- 5
|
61
|
+
- 1
|
62
|
+
version: 1.5.1
|
58
63
|
type: :runtime
|
59
64
|
version_requirements: *id003
|
60
65
|
- !ruby/object:Gem::Dependency
|
61
|
-
name:
|
66
|
+
name: yajl-ruby
|
62
67
|
prerelease: false
|
63
68
|
requirement: &id004 !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
64
70
|
requirements:
|
65
71
|
- - "="
|
66
72
|
- !ruby/object:Gem::Version
|
73
|
+
hash: 15
|
67
74
|
segments:
|
68
|
-
-
|
69
|
-
-
|
70
|
-
-
|
71
|
-
version:
|
75
|
+
- 0
|
76
|
+
- 7
|
77
|
+
- 6
|
78
|
+
version: 0.7.6
|
72
79
|
type: :runtime
|
73
80
|
version_requirements: *id004
|
74
81
|
description:
|
@@ -89,9 +96,15 @@ files:
|
|
89
96
|
- VERSION.yml
|
90
97
|
- gems/moonshado-sms-0.0.1/.gitignore
|
91
98
|
- lib/moonshado-sms.rb
|
99
|
+
- lib/moonshado/configuration.rb
|
92
100
|
- lib/moonshado/keywords.rb
|
101
|
+
- lib/moonshado/sender.rb
|
93
102
|
- lib/moonshado/sms.rb
|
103
|
+
- moonshado-sms.gemspec
|
94
104
|
- test/helper.rb
|
105
|
+
- test/configuration_test.rb
|
106
|
+
- test/keywords_test.rb
|
107
|
+
- test/sms_test.rb
|
95
108
|
has_rdoc: true
|
96
109
|
homepage: http://github.com/moonshado/moonshado-sms
|
97
110
|
licenses: []
|
@@ -102,27 +115,32 @@ rdoc_options:
|
|
102
115
|
require_paths:
|
103
116
|
- lib
|
104
117
|
required_ruby_version: !ruby/object:Gem::Requirement
|
118
|
+
none: false
|
105
119
|
requirements:
|
106
120
|
- - ">="
|
107
121
|
- !ruby/object:Gem::Version
|
122
|
+
hash: 3
|
108
123
|
segments:
|
109
124
|
- 0
|
110
125
|
version: "0"
|
111
126
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
112
128
|
requirements:
|
113
129
|
- - ">="
|
114
130
|
- !ruby/object:Gem::Version
|
131
|
+
hash: 3
|
115
132
|
segments:
|
116
133
|
- 0
|
117
134
|
version: "0"
|
118
135
|
requirements: []
|
119
136
|
|
120
137
|
rubyforge_project:
|
121
|
-
rubygems_version: 1.3.
|
138
|
+
rubygems_version: 1.3.7
|
122
139
|
signing_key:
|
123
140
|
specification_version: 3
|
124
141
|
summary: Moonshado SMS gem
|
125
142
|
test_files:
|
143
|
+
- test/configuration_test.rb
|
126
144
|
- test/helper.rb
|
127
|
-
- test/
|
128
|
-
- test/
|
145
|
+
- test/keywords_test.rb
|
146
|
+
- test/sms_test.rb
|