activesms 0.0.2 → 0.6.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.
@@ -0,0 +1,3 @@
1
+ *0.0.1*
2
+
3
+ * Initial release [Robert Cottrell]
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007 Robert Cottrell
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 PURPOa AND
17
+ NONINFRINGEMENT. IN NO EVENT SaALL 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.
@@ -1,12 +1,31 @@
1
+ CHANGELOG
1
2
  History.txt
2
3
  License.txt
4
+ MIT-LICENSE
3
5
  Manifest.txt
4
6
  README.txt
5
7
  Rakefile
8
+ generators/sms/USAGE
9
+ generators/sms/sms_generator.rb
10
+ generators/sms/templates/fixture.rhtml
11
+ generators/sms/templates/model.rb
12
+ generators/sms/templates/unit_test.rb
13
+ init.rb
6
14
  lib/activesms.rb
15
+ lib/activesms/adv_attr_accessor.rb
16
+ lib/activesms/base.rb
17
+ lib/activesms/connection_adapters/abstract_adapter.rb
18
+ lib/activesms/connection_adapters/bulk_sms_adapter.rb
19
+ lib/activesms/connection_adapters/clickatell_adapter.rb
20
+ lib/activesms/connection_adapters/simplewire_adapter.rb
21
+ lib/activesms/connections.rb
22
+ lib/activesms/exceptions.rb
23
+ lib/activesms/sms.rb
24
+ lib/activesms/validations.rb
7
25
  lib/activesms/version.rb
8
26
  scripts/txt2html
9
27
  setup.rb
28
+ test/connection_adapters/test_simplewire_adapter.rb
10
29
  test/test_activesms.rb
11
30
  test/test_helper.rb
12
31
  website/index.html
@@ -0,0 +1,19 @@
1
+ Active SMS Generator
2
+
3
+ Description:
4
+ The SMS generator creates stubs for a new SMS model.
5
+
6
+ The generator takes an SMS model name and a list of SMS methods as
7
+ arguments. The model name may be given in CamelCase or under_score.
8
+
9
+ The generator creates an SMS model class in app/models and a test suite
10
+ with fixtures in test/unit.
11
+
12
+ Example:
13
+ ./script/generate sms Notifier signup forgot_password
14
+
15
+ This will create a Nofier SMS class:
16
+ Model: app/models/notifier.rb
17
+ Test: test/unit/notifier_test.rb
18
+ Fixtures: test/fixtures/notifier/signup
19
+ test/fixtures/notifier/forgot_password
@@ -0,0 +1,31 @@
1
+ class SmsGenerator < Rails::Generator::NamedBase
2
+ def manifest
3
+ record do |m|
4
+ # Check for class naming collisions.
5
+ m.class_collisions class_path, class_name, "#{class_name}Test"
6
+
7
+ # Create model, view, test, and fixture directories.
8
+ m.directory File.join('app/models', class_path)
9
+ m.directory File.join('test/unit', class_path)
10
+ m.directory File.join('test/fixtures', file_path)
11
+
12
+ # Create model class and unit test.
13
+ m.template "model.rb", File.join('app/models',
14
+ class_path,
15
+ "#{file_name}.rb")
16
+ m.template "unit_test.rb", File.join('test/unit',
17
+ class_path,
18
+ "#{file_name}_test.rb")
19
+
20
+ # Create fixture for each action.
21
+ actions.each do |action|
22
+ relative_path = File.join(file_path, action)
23
+ fixture_path = File.join('test/fixtures', relative_path)
24
+
25
+ m.template "fixture.rhtml", fixture_path,
26
+ :assigns => { :action => action, :path => fixture_path }
27
+ end
28
+ end
29
+ end
30
+
31
+ end
@@ -0,0 +1 @@
1
+ <%= class_name %>#<%= action %>
@@ -0,0 +1,11 @@
1
+ class <%= class_name %> < ActiveSms::Base
2
+ <% actions.each do |action| -%>
3
+
4
+ def <%= action %>
5
+ @recipients = ''
6
+ @from = ''
7
+ @body = "<%= class_name %>#<%= action %>"
8
+ @options = {}
9
+ end
10
+ <% end -%>
11
+ end
@@ -0,0 +1,31 @@
1
+ require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../test_helper'
2
+
3
+ class <%= class_name %>Test < Test::Unit::TestCase
4
+ FIXTURES_PATH = File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../fixtures'
5
+
6
+ def setup
7
+ ActiveSms::Base.delivery_method = :test
8
+ ActiveSms::Base.perform_deliveries = true
9
+ ActiveSms::Base.deliveries = []
10
+
11
+ @expected = ActiveSms::Sms.new
12
+ end
13
+
14
+ <% actions.each do |action| -%>
15
+ def test_<%= action %>
16
+ @expected.recipients = ''
17
+ @expected.from = ''
18
+ @expected.body = read_fixture('<%= action %>')
19
+
20
+ actual = <%= class_name %>.create_<%= action %>
21
+ assert_equal @expected.recipients, actual.recipients
22
+ assert_equal @expected.from, actual.from
23
+ assert_equal @expected.body, actual.body
24
+ end
25
+
26
+ <% end -%>
27
+ private
28
+ def read_fixture(action)
29
+ IO.read("#{FIXTURES_PATH}/<%= file_path %>/#{action}")
30
+ end
31
+ end
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'activesms'
2
+ ActiveSms::Base.logger = RAILS_DEFAULT_LOGGER
@@ -0,0 +1,32 @@
1
+ module ActiveSms
2
+ module AdvAttrAccessor #:nodoc:
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ module ClassMethods #:nodoc:
8
+ def adv_attr_accessor(*names)
9
+ names.each do |name|
10
+ ivar = "@#{name}"
11
+
12
+ define_method("#{name}=") do |value|
13
+ instance_variable_set(ivar, value)
14
+ end
15
+
16
+ define_method(name) do |*parameters|
17
+ if parameters.length > 1
18
+ raise ArgumentError, "expected 0 or 1 parameters"
19
+ end
20
+ if parameters.empty?
21
+ if instance_variables.include?(ivar)
22
+ instance_variable_get(ivar)
23
+ end
24
+ else
25
+ instance_variable_set(ivar, parameters.first)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,217 @@
1
+ require 'activesms/adv_attr_accessor'
2
+ require 'activesms/sms'
3
+ require 'net/https'
4
+
5
+ module ActiveSms #:nodoc:
6
+
7
+ # Active SMS allows you to send SMS messages from your application using
8
+ # an SMS model.
9
+ #
10
+ # = SMS models
11
+ #
12
+ # To use Action SMS, you need to create an SMS model.
13
+ #
14
+ # $ script/generate sms Notifier signup
15
+ #
16
+ # The generated model inherits from ActiveSms::Base. SMS messages are
17
+ # defined by creating methods on the model which are then used to set
18
+ # variables to be used in the message or to change options on the message.
19
+ #
20
+ # Examples:
21
+ #
22
+ # class Notifier < ActiveSms::Base
23
+ # def signup
24
+ # recipients "447987654321"
25
+ # from "447123456789"
26
+ # body "Your account has been created"
27
+ # end
28
+ # end
29
+ #
30
+ # Sender methods have the following configuration methods available.
31
+ #
32
+ # * <tt>recipients</tt> - Takes one or more destination numbers. These
33
+ # numbers should be formatted in standard international number format.
34
+ #
35
+ # * <tt>from</tt> - Who the SMS message you are sending is from. This
36
+ # may be either a number formatted in standard internation number format,
37
+ # or, if the gateway supports it, an alphanumeric origination.
38
+ #
39
+ # * <tt>body</tt> - The content of the message. This must fit within the
40
+ # length limitation of SMS messages.
41
+ #
42
+ # = Sending SMS messages
43
+ #
44
+ # Once an SMS action is defined, you can deliver you message or create it
45
+ # and save it for delivery later.
46
+ #
47
+ # Notifier.deliver_signup_noification(david) # sends the SMS message
48
+ #
49
+ # sms = Notifier.create_signup_notification(david) # an SMS object
50
+ # Notifier.deliver(sms)
51
+ #
52
+ # You never instantiate your model class. Rather, your delivery instance
53
+ # methods are automatically wrapped in class methods that start with the
54
+ # word <tt>deliver</tt> followed by the name of the SMS method that you
55
+ # would like to deliver. The <tt>signup_notification</tt> method defined
56
+ # above is delivered by invoking <tt>Notifier.deliver_signup_notification</tt>.
57
+ #
58
+ # = Configuration options
59
+ #
60
+ # These options are specified on the class level.
61
+ #
62
+ # * <tt>logger</tt> - The logger is used for generating information about
63
+ # the sending run if available. This can be set to nil for no logging.
64
+ # It is compatible with Ruby's own Logger and Log4r loggers.
65
+ #
66
+ # * <tt>gateway_settings</tt> - Allows detailed configuration of the SMS
67
+ # gateway used to deliver the messages. Some gateways may require
68
+ # additional configuration settings.
69
+ #
70
+ # * <tt>raise_delivery_errors</tt> - Determines whether or not errors should
71
+ # be raised if the SMS fails to be delivered.
72
+ #
73
+ # * <tt>delivery_method</tt> - Defines a delivery method. Possible values
74
+ # are :gateway (default) or :test.
75
+ #
76
+ # * <tt>perform_deliveries</tt> - Determines whether or not deliver_*
77
+ # methods are actually carried out. By default they are, but this can be
78
+ # turned off to help functional testing.
79
+ #
80
+ # * <tt>deliveries</tt> - Keeps an array of all the messages sent out through
81
+ # Active SMS with deliver_method :test. Most useful for unit and functional
82
+ # testing.
83
+ class Base
84
+ include AdvAttrAccessor
85
+ include ActionController::UrlWriter
86
+
87
+ @@logger = nil
88
+ cattr_accessor :logger
89
+
90
+ private_class_method :new #:nodoc:
91
+
92
+ @@raise_delivery_errors = true
93
+ cattr_accessor :raise_delivery_errors
94
+
95
+ @@delivery_method = :gateway
96
+ cattr_accessor :delivery_method
97
+
98
+ @@perform_deliveries = true
99
+ cattr_accessor :perform_deliveries
100
+
101
+ @@deliveries = []
102
+ cattr_accessor :deliveries
103
+
104
+ # The recipient numbers for the message, either as a string (for a single
105
+ # recipient) or an array (for multiple recipients).
106
+ adv_attr_accessor :recipients
107
+
108
+ # Specify the from number or identifier for the message.
109
+ adv_attr_accessor :from
110
+
111
+ # Specify the subject of the message.
112
+ adv_attr_accessor :subject
113
+
114
+ # The content of the message.
115
+ adv_attr_accessor :body
116
+
117
+ # The Sms message object instance referenced by this model.
118
+ attr_reader :sms
119
+
120
+ class << self
121
+ def method_missing(method_symbol, *parameters) #:nodoc:
122
+ case method_symbol.id2name
123
+ when /^create_([_a-z]\w+)/ then new($1, *parameters).sms
124
+ when /^deliver_([_a-z]\w+)/ then new($1, *parameters).deliver!
125
+ when "new" then nil
126
+ else super
127
+ end
128
+ end
129
+
130
+ # Receives an SMS message, parses it into an SMS object, instantiates
131
+ # a new model, and passes the message object to the model object's
132
+ # #receive method. If you want your model to be able to process
133
+ # incoming messages, you'll need to implement a #receive method
134
+ # that accepts the SMS object as a parameter.
135
+ #
136
+ # class Notifier < ActionSms::Base
137
+ # def receive(sms)
138
+ # ...
139
+ # end
140
+ # end
141
+ def receive(sms)
142
+ sms = connection.parse(sms)
143
+ new.receive(sms)
144
+ end
145
+
146
+ # Deliver the given Sms message object directly. This can be used to
147
+ # deliver a preconstructed message, like:
148
+ #
149
+ # sms = Notifier.create_signup_notification(parameters)
150
+ # Notifier.deliver(sms)
151
+ def deliver(sms)
152
+ new.deliver!(sms)
153
+ end
154
+
155
+ end
156
+
157
+ # Instantiate a new Active SMS model object. If +method_name+ is not
158
+ # +nil+, the model will be initialized according to the named method.
159
+ # If not, the model will remain uninitialized (useful when you need to
160
+ # invoke the "receive" method, for instance).
161
+ def initialize(method_name = nil, *parameters) #:nodoc:
162
+ create!(method_name, *parameters) if method_name
163
+ end
164
+
165
+ # Initialize the model via the given +method_name+. The body will be
166
+ # rendered and a new Sms object created.
167
+ def create!(method_name, *parameters) #:nodoc:
168
+ initialize_defaults(method_name)
169
+ send(method_name, *parameters)
170
+
171
+ # Build the SMS object itself.
172
+ @sms = create_sms
173
+ end
174
+
175
+ # Delivers an Sms message object. By default, it deliver the cached object
176
+ # (from the #create! method). If no cached object exists, and no
177
+ # alternate has been give as the prameter, this will fail.
178
+ def deliver!(sms = @sms) #:nodoc:
179
+ raise "no SMS object available for delivery!" unless sms
180
+ logger.info "Sending SMS: #{sms}" unless logger.nil?
181
+
182
+ begin
183
+ send("perform_delivery_#{delivery_method}", sms) if perform_deliveries
184
+ rescue Exception => e
185
+ raise e if raise_delivery_errors
186
+ end
187
+
188
+ return sms
189
+ end
190
+
191
+ private
192
+
193
+ # Set up the default values for the various instance variables of this
194
+ # model. Subclasses may override this method to provide different
195
+ # defaults.
196
+ def initialize_defaults(method_name)
197
+ end
198
+
199
+ def create_sms
200
+ sms = Sms.new
201
+ sms.recipients = recipients
202
+ sms.from = from
203
+ sms.body = body
204
+ @sms = sms
205
+ end
206
+
207
+ def perform_delivery_gateway(sms)
208
+ raise ConnectionNotEstablished unless connection
209
+ connection.deliver(sms)
210
+ end
211
+
212
+ def perform_delivery_test(sms)
213
+ deliveries << sms
214
+ end
215
+
216
+ end
217
+ end
@@ -0,0 +1,52 @@
1
+ require 'net/https'
2
+
3
+ module ActiveSms #:nodoc:
4
+ module ConnectionAdapters #:nodoc:
5
+ # All the concrete gateway adapters follow the interface laid down in this
6
+ # class. You can use this interface directly by borrowing the gateway
7
+ # connection from the Base with Base.connection.
8
+ class AbstractAdapter
9
+
10
+ @logger = nil
11
+ attr_accessor :logger
12
+
13
+ def initialize(logger = nil) #:nodoc:
14
+ @logger = logger
15
+ end
16
+
17
+ # Return the human readable name of the gateway adapter.
18
+ def adapter_name
19
+ return 'Abstract'
20
+ end
21
+
22
+ def deliver(sms)
23
+ end
24
+
25
+ def parse(sms)
26
+ nil
27
+ end
28
+
29
+ protected
30
+
31
+ # Helper method to send an HTTP request to +url+ with paramaters
32
+ # specified by the +params+ hash.
33
+ def send_http_request(url, params)
34
+ uri = URI.parse(url)
35
+ req = Net::HTTP::Post.new(uri.path)
36
+ req.set_form_data(params)
37
+
38
+ http = Net::HTTP.new(uri.host, uri.port)
39
+ http.use_ssl = true if uri.scheme == 'https'
40
+ resp = http.start do
41
+ http.request(req)
42
+ end
43
+ @logger.info "Response: #{resp.body}" unless @logger.nil?
44
+
45
+ return resp.body
46
+ rescue Exception => e
47
+ raise e
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,67 @@
1
+ require 'activesms/connection_adapters/abstract_adapter'
2
+
3
+ module ActiveSms
4
+ class Base
5
+ def self.bulk_sms_connection(config) #:nodoc:
6
+ return ConnectionAdapters::BulkSmsAdapter.new(logger, config)
7
+ end
8
+ end
9
+
10
+ module ConnectionAdapters
11
+ class BulkSmsAdapter < AbstractAdapter
12
+
13
+ SERVICE_HOSTS = {
14
+ :international => 'bulksms.vsms.net',
15
+ :safrica => 'bulksms.2way.co.za',
16
+ :spoin => 'bulksms.com.es',
17
+ :uk => 'www.bulksms.co.uk',
18
+ :usa => 'usa.bulksms.com'
19
+ }
20
+ SERVICE_PORT = 5567
21
+ SERVICE_PATH = '/eapi/submission/send_sms/2/2.0'
22
+
23
+ STATUS_MESSAGES = {
24
+ 0 => 'in progress',
25
+ 1 => 'scheduled',
26
+ 22 => 'internal fatal error',
27
+ 23 => 'authentication failure',
28
+ 24 => 'data validation failed',
29
+ 25 => 'insufficient credits',
30
+ 26 => 'upstream credits not available',
31
+ 27 => 'daily quota exceeded',
32
+ 28 => 'upstream quota exceeded',
33
+ 40 => 'temporarily unavailable'
34
+ }
35
+
36
+ # Create an adapter for the BulkSMS gateway.
37
+ #
38
+ # Options:
39
+ # * <tt>:region</tt>
40
+ # * <tt>:username</tt>
41
+ # * <tt>:password</tt>
42
+ def initialize(logger = nil, config = {})
43
+ super(logger)
44
+ @config = config.dup
45
+
46
+ host = SERVICE_HOSTS[config[:region]] || SERVICE_HOSTS[:uk]
47
+ @service_url = "http://#{host}:#{SERVICE_PORT}#{SERVICE_PATH}"
48
+ end
49
+
50
+ # Return the human readable name of the connection adapter name.
51
+ def adpter_name
52
+ return 'BulkSMS'
53
+ end
54
+
55
+ def deliver(sms)
56
+ params = {
57
+ :username => @config[:username],
58
+ :password => @config[:password],
59
+ :msisdn => sms.recipients,
60
+ :message => sms.body,
61
+ }
62
+ send_http_request(@service_url, params)
63
+ end
64
+
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,51 @@
1
+ require 'activesms/connection_adapters/abstract_adapter'
2
+
3
+ module ActiveSms
4
+ class Base
5
+ def self.clickatell_connection(config) #:nodoc:
6
+ return ConnectionAdapters::ClickatellAdapter.new(logger, config)
7
+ end
8
+ end
9
+
10
+ module ConnectionAdapters
11
+ class ClickatellAdapter < AbstractAdapter
12
+
13
+ SERVICE_HOST = "api.clickatell.com"
14
+ SERVICE_PATH = "/http/sendmsg"
15
+
16
+ # Create an adapter for the Clickatell gateway.
17
+ #
18
+ # Options:
19
+ #
20
+ # * <tt>:user</tt>
21
+ # * <tt>:password</tt>
22
+ # * <tt>:api_id</tt>
23
+ # * <tt>use_ssl</tt>
24
+ def initialize(logger = nil, config = {})
25
+ super(logger)
26
+ @config = config.dup
27
+
28
+ scheme = config[:use_ssl] ? "https" : "http"
29
+ @service_url = "#{scheme}://#{SERVICE_HOST}#{SERVICE_PATH}"
30
+ end
31
+
32
+ # Return the human readable name of the gateway adapter name.
33
+ def adpter_name
34
+ return 'Clickatell'
35
+ end
36
+
37
+ def deliver(sms)
38
+ params = {
39
+ :user => @config[:user],
40
+ :password => @config[:password],
41
+ :api_id => @config[:api_id],
42
+ :to => sms.recipients,
43
+ :from => sms.from,
44
+ :text => sms.body
45
+ }
46
+ send_http_request(@service_url, params)
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,58 @@
1
+ require 'activesms/connection_adapters/abstract_adapter'
2
+
3
+ begin
4
+ require 'java'
5
+ include_class 'com.simplewire.sms.SMS'
6
+ rescue LoadError
7
+ puts "JRuby is required for the simplewire adapter"
8
+ raise $!
9
+ end
10
+
11
+ module ActiveSms
12
+ class Base
13
+ def self.simplewire_connection(config) #:nodoc:
14
+ return ConnectionAdapters::SimplewireAdapter.new(logger, config)
15
+ end
16
+ end
17
+
18
+ module ConnectionAdapters
19
+ class SimplewireAdapter < AbstractAdapter
20
+
21
+ # Create a simplewire adapter. The config requires subscriber_id and subscriber_password.
22
+ def initialize(logger = nil, config = {})
23
+ super(logger)
24
+ @config = config.dup
25
+ @config.symbolize_keys!
26
+
27
+ unless @config.member?(:subscriber_id)
28
+ raise "subscriber_id is required for simplewire"
29
+ end
30
+ unless @config.member?(:subscriber_password)
31
+ raise "subscriber_password is required for simplewire"
32
+ end
33
+ end
34
+
35
+ # Return the human readable name of the gateway adapter name.
36
+ def adpter_name
37
+ return 'Simplewire'
38
+ end
39
+
40
+ # Send the sms message using the simplewire adapter
41
+ def deliver(sms)
42
+ create_sms(sms).submit()
43
+ end
44
+
45
+ def parse(sms)
46
+ end
47
+
48
+ # Create the simplewire sms message to send
49
+ def create_sms(sms)
50
+ s = SMS.new
51
+ s.destination_addr = sms.recipients
52
+ s.source_addr = sms.from
53
+ s.msg_text = sms.body
54
+ s
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,64 @@
1
+ module ActiveSms #:nodoc#
2
+
3
+ class Base
4
+ @@connection = nil
5
+
6
+ class << self
7
+ # Returns true if a connection that's accessible to this class has already
8
+ # been opened.
9
+ def connected?
10
+ return !@@connection.nil?
11
+ end
12
+
13
+ # Returns the connection currently associated with the class. This can
14
+ # also be used to "borrow" the connection to do work that is specific to
15
+ # a particular SMS gateway.
16
+ def connection
17
+ raise ConnectionNotEstablished unless @@connection
18
+ return @@connection
19
+ end
20
+
21
+ # Set the gateway connection for the class.
22
+ def connection=(spec) #:nodoc:
23
+ raise ConnectionNotEstablished unless spec
24
+ @@connection = spec
25
+ end
26
+
27
+ # Establishes the connection to the SMS gateway. Accepts a hash as input
28
+ # where the :adapter key must be specified with the name of a gateway
29
+ # adapter (in lower-case)
30
+ #
31
+ # ActiveSms::Base.establish_connection(
32
+ # :adapter => "clickatell",
33
+ # :username => "myusername",
34
+ # :password => "mypassword"
35
+ # :api_id => "myapiid"
36
+ # )
37
+ #
38
+ # Also accepts keys as strings (for parsing from YAML, for example).
39
+ #
40
+ # The exceptions AdapterNotSpecified, AdapterNotFound, and ArgumentError
41
+ # may be returned.
42
+ def establish_connection(config)
43
+ config = config.symbolize_keys
44
+ unless config.key?(:adapter)
45
+ raise AdapterNotSpecified, "#{config} adapter is not configured"
46
+ end
47
+ adapter_method = "#{config[:adapter]}_connection"
48
+ unless respond_to?(adapter_method)
49
+ raise AdapterNotFound,
50
+ "configuration specifies nonexistent #{config[:adapter]} adapter"
51
+ end
52
+ self.connection = self.send(adapter_method, config)
53
+ end
54
+ end
55
+
56
+ # Returns the connection currently associated with the class. This can
57
+ # also be used to "borrow" the connection to do work that is specific to
58
+ # a particular SMS gateway.
59
+ def connection
60
+ self.class.connection
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,23 @@
1
+ module ActiveSms #:nodoc:
2
+
3
+ # Generic error class and superclass of all other errors raised by
4
+ # Active SMS
5
+ class ActiveSmsError < StandardError
6
+ end
7
+
8
+ # The configuration hash used in <tt>establish_connection</tt> didn't include
9
+ # <tt>:adapter</tt> key
10
+ class AdapterNotSpecified < ActiveSmsError
11
+ end
12
+
13
+ # The <tt>adapter</tt> key used in <tt>establish_connection</tt> specified a
14
+ # nonexistent adapter.
15
+ class AdapterNotFound < ActiveSmsError
16
+ end
17
+
18
+ # No connection has been established. Use <tt>establish_connection</tt>
19
+ # before sending a message.
20
+ class ConnectionNotEstablished < ActiveSmsError
21
+ end
22
+
23
+ end
@@ -0,0 +1,11 @@
1
+ module ActiveSms
2
+ class Sms
3
+ attr_accessor :recipients
4
+ attr_accessor :from
5
+ attr_accessor :body
6
+
7
+ def to_s
8
+ "#<#{self.class.name} @recipients=#{recipients.inspect} @from=#{from.inspect} @body=#{body.inspect}>"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,49 @@
1
+ module ActiveSms
2
+ # The SMS message object is invalid. Use the sms method to retrieve the
3
+ # message which did not validate.
4
+ class SmsInvalid < ActiveSmsError
5
+ attr_reader :sms
6
+ def initialize(sms)
7
+ @sms = sms
8
+ super("Validation failed: #{@sms.errors.full_messages.join(', ')}")
9
+ end
10
+ end
11
+
12
+ # Active SMS validation is reported to and from this object, which is used
13
+ # by Base to determine whether the message is in a valid state to be sent.
14
+ class Errors
15
+ include Enumerable
16
+
17
+ # Holds a hash with all the default error message. This can be replaced
18
+ # by your own copy or localizations.
19
+ @@default_error_messages = {
20
+ :invalid => "is invalid"
21
+ }
22
+ cattr_accessor :default_error_messages
23
+
24
+ def initialize(base) #:nodoc:
25
+ @base = base
26
+ @errors = {}
27
+ end
28
+
29
+ # Adds an error message to the base object instead of any particular
30
+ # attribute for the object. This is used to report errors that don't
31
+ # tie to any specific attribute, but to the object as a whole. These
32
+ # error messages don't get prepended with any field name when iterating
33
+ # with each_full, so they should be complete sentences.
34
+ def add_to_base(msg)
35
+ add(:base, msg)
36
+ end
37
+
38
+ # Adds an error message +msg+ to the +attribute+, which will be returned
39
+ # on a call to <tt>on(attribute)</tt> for the same attribute and ensure
40
+ # that this error object returns false when asked if <tt>empty?</tt>.
41
+ # More than one error can be added to the same +attribute+, in which
42
+ # case an array will be returned on a call to <tt>on(attribute)</tt>.
43
+ # If no +msg+ is supplied, "invalid" is assumed.
44
+ def add(attribute, msg = @@default_error_messages[:invalid])
45
+ @errors[attribute.to_s] ||= []
46
+ @errors[attribute.to_s] << msg
47
+ end
48
+ end
49
+ end
@@ -1,8 +1,8 @@
1
1
  module ActiveSms #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
- MINOR = 0
5
- TINY = 2
4
+ MINOR = 6
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -5,7 +5,7 @@
5
5
  <link rel="stylesheet" href="stylesheets/screen.css" type="text/css" media="screen" />
6
6
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
7
7
  <title>
8
- activesms
8
+ ActiveSms
9
9
  </title>
10
10
  <script src="javascripts/rounded_corners_lite.inc.js" type="text/javascript"></script>
11
11
  <style>
@@ -30,7 +30,7 @@
30
30
  <body>
31
31
  <div id="main">
32
32
 
33
- <h1>activesms</h1>
33
+ <h1>ActiveSms</h1>
34
34
  <div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/activesms"; return false'>
35
35
  <p>Get Version</p>
36
36
  <a href="http://rubyforge.org/projects/activesms" class="numbers">0.0.2</a>
@@ -38,33 +38,60 @@
38
38
  <h2>What</h2>
39
39
 
40
40
 
41
+ <p>Active <span class="caps">SMS</span> is a framework for creating and sending <span class="caps">SMS</span> messages.</p>
42
+
43
+
41
44
  <h2>Installing</h2>
42
45
 
43
46
 
44
47
  <pre syntax="ruby">sudo gem install activesms</pre>
45
48
 
46
- <h2>The basics</h2>
49
+ <h2>Demonstration of usage</h2>
47
50
 
48
51
 
49
- <h2>Demonstration of usage</h2>
52
+ <p><span class="caps">TBD</span>.</p>
50
53
 
51
54
 
52
- <h2>Forum</h2>
55
+ <h2>Supported Gateways</h2>
56
+
57
+
58
+ <p>Active <span class="caps">SMS</span> will require a valid account from a third party <span class="caps">SMS</span> gateway to
59
+ send or receive <span class="caps">SMS</span> messages. The following gateways are currently supported:</p>
53
60
 
54
61
 
55
- <p><a href="http://groups.google.com/group/activesms">http://groups.google.com/group/activesms</a></p>
62
+ <ul>
63
+ <li>BulkSMS[http://www.bulksms.com]</li>
64
+ <li>Clickatell[http://www.clickatell.com]</li>
65
+ <li>Simplewire[http://www.simplewire.com] (requires jruby)</li>
66
+ </ul>
56
67
 
57
68
 
58
- <p><span class="caps">TODO</span> &#8211; create Google Group &#8211; activesms</p>
69
+ <p>Not all features are supported by all gateways.</p>
59
70
 
60
71
 
61
- <h2>How to submit patches</h2>
72
+ <h3>Simplewire Configuration</h3>
62
73
 
63
74
 
64
- <p>Read the <a href="http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/">8 steps for fixing other people&#8217;s code</a> and for section <a href="http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/#8b-google-groups">8b: Submit patch to Google Groups</a>, use the Google Group above.</p>
75
+ <ul>
76
+ <li>Make sure you are using jruby</li>
77
+ <li>Make sure swsms.jar is in your classpath (Download at: <a href="http://www.simplewire.com/developers/sdk/java/">http://www.simplewire.com/developers/sdk/java/</a>)</li>
78
+ <li>Add the following configuration code to the rails environment.</li>
79
+ </ul>
65
80
 
66
81
 
67
- <p>The trunk repository is <code>svn://rubyforge.org/var/svn/activesms/trunk</code> for anonymous access.</p>
82
+ <pre syntax="ruby">
83
+ ActiveSms::Base.establish_connection(
84
+ :adapter =&gt; "simplewire",
85
+ :subscriber_id =&gt; "id",
86
+ :subscriber_password =&gt; "password"
87
+ )
88
+
89
+ </pre>
90
+
91
+ <h2>Forum</h2>
92
+
93
+
94
+ <p><a href="http://rubyforge.org/forum/?group_id=2923">http://rubyforge.org/forum/?group_id=2923</a></p>
68
95
 
69
96
 
70
97
  <h2>License</h2>
@@ -73,14 +100,11 @@
73
100
  <p>This code is free to use under the terms of the <span class="caps">MIT</span> license.</p>
74
101
 
75
102
 
76
- <h2>Contact</h2>
103
+ <h2>Support</h2>
104
+
77
105
 
106
+ <p>You can find the Active <span class="caps">SMS</span> RubyForge page at <a href="http://rubyforge.org/projects/activesms">http://rubyforge.org/projects/activesms</a>.</p>
78
107
 
79
- <p>Comments are welcome. Send an email to <a href="mailto:FIXME"><span class="caps">FIXME</span> full name</a> email.</p>
80
- <p class="coda">
81
- <a href="mailto:drnicwilliams@gmail.com">Dr Nic</a>, 26th July 2007<br>
82
- Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
83
- </p>
84
108
  </div>
85
109
 
86
110
  <!-- insert site tracking codes here, like Google Urchin -->
@@ -1,35 +1,51 @@
1
- h1. activesms
1
+ h1. ActiveSms
2
2
 
3
3
  h2. What
4
4
 
5
+ Active SMS is a framework for creating and sending SMS messages.
5
6
 
6
7
  h2. Installing
7
8
 
8
9
  <pre syntax="ruby">sudo gem install activesms</pre>
9
10
 
10
- h2. The basics
11
+ h2. Demonstration of usage
11
12
 
13
+ TBD.
12
14
 
13
- h2. Demonstration of usage
15
+ h2. Supported Gateways
14
16
 
17
+ Active SMS will require a valid account from a third party SMS gateway to
18
+ send or receive SMS messages. The following gateways are currently supported:
15
19
 
20
+ * BulkSMS[http://www.bulksms.com]
21
+ * Clickatell[http://www.clickatell.com]
22
+ * Simplewire[http://www.simplewire.com] (requires jruby)
16
23
 
17
- h2. Forum
24
+ Not all features are supported by all gateways.
18
25
 
19
- "http://groups.google.com/group/activesms":http://groups.google.com/group/activesms
26
+ h3. Simplewire Configuration
20
27
 
21
- TODO - create Google Group - activesms
28
+ * Make sure you are using jruby
29
+ * Make sure swsms.jar is in your classpath (Download at: "http://www.simplewire.com/developers/sdk/java/":http://www.simplewire.com/developers/sdk/java/)
30
+ * Add the following configuration code to the rails environment.
22
31
 
23
- h2. How to submit patches
32
+ <pre syntax="ruby">
33
+ ActiveSms::Base.establish_connection(
34
+ :adapter => "simplewire",
35
+ :subscriber_id => "id",
36
+ :subscriber_password => "password"
37
+ )
38
+
39
+ </pre>
24
40
 
25
- Read the "8 steps for fixing other people's code":http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/ and for section "8b: Submit patch to Google Groups":http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/#8b-google-groups, use the Google Group above.
41
+ h2. Forum
26
42
 
27
- The trunk repository is <code>svn://rubyforge.org/var/svn/activesms/trunk</code> for anonymous access.
43
+ "http://rubyforge.org/forum/?group_id=2923":http://rubyforge.org/forum/?group_id=2923
28
44
 
29
45
  h2. License
30
46
 
31
47
  This code is free to use under the terms of the MIT license.
32
48
 
33
- h2. Contact
49
+ h2. Support
34
50
 
35
- Comments are welcome. Send an email to "FIXME full name":mailto:FIXME email.
51
+ You can find the Active SMS RubyForge page at "http://rubyforge.org/projects/activesms":http://rubyforge.org/projects/activesms.
@@ -36,10 +36,7 @@
36
36
  <a href="<%= download %>" class="numbers"><%= version %></a>
37
37
  </div>
38
38
  <%= body %>
39
- <p class="coda">
40
- <a href="mailto:drnicwilliams@gmail.com">Dr Nic</a>, <%= modified.pretty %><br>
41
- Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
42
- </p>
39
+
43
40
  </div>
44
41
 
45
42
  <!-- insert site tracking codes here, like Google Urchin -->
metadata CHANGED
@@ -3,7 +3,7 @@ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: activesms
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.0.2
6
+ version: 0.6.0
7
7
  date: 2007-07-26 00:00:00 -07:00
8
8
  summary: Active SMS is a framework for sending and receiving SMS messages
9
9
  require_paths:
@@ -34,15 +34,34 @@ authors:
34
34
  - Ben Curren
35
35
  - Dean Mao
36
36
  files:
37
+ - CHANGELOG
37
38
  - History.txt
38
39
  - License.txt
40
+ - MIT-LICENSE
39
41
  - Manifest.txt
40
42
  - README.txt
41
43
  - Rakefile
44
+ - generators/sms/USAGE
45
+ - generators/sms/sms_generator.rb
46
+ - generators/sms/templates/fixture.rhtml
47
+ - generators/sms/templates/model.rb
48
+ - generators/sms/templates/unit_test.rb
49
+ - init.rb
42
50
  - lib/activesms.rb
51
+ - lib/activesms/adv_attr_accessor.rb
52
+ - lib/activesms/base.rb
53
+ - lib/activesms/connection_adapters/abstract_adapter.rb
54
+ - lib/activesms/connection_adapters/bulk_sms_adapter.rb
55
+ - lib/activesms/connection_adapters/clickatell_adapter.rb
56
+ - lib/activesms/connection_adapters/simplewire_adapter.rb
57
+ - lib/activesms/connections.rb
58
+ - lib/activesms/exceptions.rb
59
+ - lib/activesms/sms.rb
60
+ - lib/activesms/validations.rb
43
61
  - lib/activesms/version.rb
44
62
  - scripts/txt2html
45
63
  - setup.rb
64
+ - test/connection_adapters/test_simplewire_adapter.rb
46
65
  - test/test_activesms.rb
47
66
  - test/test_helper.rb
48
67
  - website/index.html