clickatell 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,12 @@
1
+ == 0.4.0
2
+
3
+ * Added API debug mode and --debug option to sms utility
4
+ * Restructured API classes into individual files
5
+ * Refactored command execution into a separate object (CommandExecutor).
6
+ * Major refactoring of API module - converted it to a class with API methods
7
+ implemented as instance methods. Code is much cleaner and Connection class
8
+ becomes redundant. See updated documentation.
9
+
1
10
  == 0.3.0
2
11
 
3
12
  * Display proper message status, not just the code
data/Manifest.txt CHANGED
@@ -6,7 +6,10 @@ Rakefile
6
6
  bin/sms
7
7
  lib/clickatell.rb
8
8
  lib/clickatell/api.rb
9
- lib/clickatell/connection.rb
9
+ lib/clickatell/api/command.rb
10
+ lib/clickatell/api/command_executor.rb
11
+ lib/clickatell/api/error.rb
12
+ lib/clickatell/api/message_status.rb
10
13
  lib/clickatell/response.rb
11
14
  lib/clickatell/utility.rb
12
15
  lib/clickatell/utility/options.rb
@@ -15,7 +18,6 @@ lib/core-ext/hash.rb
15
18
  scripts/txt2html
16
19
  setup.rb
17
20
  spec/api_spec.rb
18
- spec/connection_spec.rb
19
21
  spec/hash_ext_spec.rb
20
22
  spec/response_spec.rb
21
23
  spec/spec.opts
data/README.txt CHANGED
@@ -10,12 +10,8 @@ account username and password.
10
10
  require 'rubygems'
11
11
  require 'clickatell'
12
12
 
13
- connection = Clickatell::Connection.new(
14
- 'your_api_id',
15
- 'your_username',
16
- 'your_password'
17
- )
18
- connection.send_message('447771234567', 'Hello from clickatell')
13
+ api = Clickatell::API.authenticate('your_api_id', 'your_username', 'your_password')
14
+ api.send_message('447771234567', 'Hello from clickatell')
19
15
 
20
16
 
21
17
  == Command-line SMS Utility
data/bin/sms CHANGED
@@ -13,24 +13,30 @@ else
13
13
  require 'clickatell/utility'
14
14
  end
15
15
 
16
+ # parse command line options
16
17
  options = Clickatell::Utility::Options.parse(ARGV)
17
- connection = Clickatell::Connection.new(options.api_key, options.username, options.password)
18
+
19
+ # enable debugging if specified
20
+ Clickatell::API.debug_mode = true if options.debugging_enabled
21
+
22
+ # authenticate and load the API
23
+ api = Clickatell::API.authenticate(options.api_key, options.username, options.password)
18
24
 
19
25
  begin
20
26
  if options.show_balance
21
27
  puts "Retrieving account balance..."
22
- puts "You have #{connection.account_balance} credits remaining."
28
+ puts "You have #{api.account_balance} credits remaining."
23
29
  exit 0
24
30
  elsif options.show_status
25
31
  puts "Getting status of message ##{options.message_id}."
26
- status = connection.message_status(options.message_id)
32
+ status = api.message_status(options.message_id)
27
33
  puts "Status: #{Clickatell::API::MessageStatus[status]} (##{status})."
28
34
  exit 0
29
35
  else
30
36
  puts "Sending '#{options.message}' to #{options.recipient}..."
31
37
  additional_opts = {}
32
38
  additional_opts[:from] = options.from if options.from
33
- msg_id = connection.send_message(options.recipient, options.message, additional_opts)
39
+ msg_id = api.send_message(options.recipient, options.message, additional_opts)
34
40
  puts "Message sent successfully (message id: #{msg_id})."
35
41
  exit 0
36
42
  end
@@ -51,4 +57,9 @@ rescue Clickatell::API::Error => e
51
57
  puts "Please contact the author (contact@lukeredpath.co.uk) with the above error."
52
58
  exit 1
53
59
  end
60
+
61
+ rescue Timeout::Error
62
+ puts "The connection the the Clickatell service timed out"
63
+ puts "Please check your network settings and try again."
64
+ exit 1
54
65
  end
data/lib/clickatell.rb CHANGED
@@ -1,8 +1,10 @@
1
- module Clickatell
2
- end
1
+ module Clickatelll end
3
2
 
4
- require File.join(File.dirname(__FILE__), *%w[core-ext/hash])
5
- require File.join(File.dirname(__FILE__), *%w[clickatell/version])
6
- require File.join(File.dirname(__FILE__), *%w[clickatell/api])
7
- require File.join(File.dirname(__FILE__), *%w[clickatell/response])
8
- require File.join(File.dirname(__FILE__), *%w[clickatell/connection])
3
+ %w( core-ext/hash
4
+ clickatell/version
5
+ clickatell/api
6
+ clickatell/response
7
+
8
+ ).each do |lib|
9
+ require File.join(File.dirname(__FILE__), lib)
10
+ end
@@ -1,160 +1,111 @@
1
- require 'net/http'
2
-
3
1
  module Clickatell
4
- # This module provides the core implementation of the Clickatell
2
+ # This module provides the core implementation of the Clickatell
5
3
  # HTTP service.
6
- module API
4
+ class API
5
+ attr_accessor :auth_options
7
6
 
8
7
  class << self
9
-
10
- # Authenticates using the specified credentials. Returns
11
- # a session_id if successful which can be used in subsequent
12
- # API calls.
8
+ # Authenticates using the given credentials and returns an
9
+ # API instance with the authentication options set to use the
10
+ # resulting session_id.
13
11
  def authenticate(api_id, username, password)
14
- response = execute_command('auth',
15
- :api_id => api_id,
16
- :user => username,
17
- :password => password
18
- )
19
- parse_response(response)['OK']
20
- end
21
-
22
- # Pings the service with the specified session_id to keep the
23
- # session alive.
24
- def ping(session_id)
25
- execute_command('ping', :session_id => session_id)
26
- end
27
-
28
- # Sends a message +message_text+ to +recipient+. Recipient
29
- # number should have an international dialing prefix and
30
- # no leading zeros (unless you have set a default prefix
31
- # in your clickatell account centre).
32
- #
33
- # Takes a hash of auth_options to be used in this
34
- # API call. Either api_id/username/password or session_id
35
- # for an existing authenticated session.
36
- #
37
- # Additional options:
38
- # :from - the from number/name
39
- #
40
- # Returns a new message ID if successful.
41
- def send_message(recipient, message_text, auth_options, opts={})
42
- valid_options = opts.only(:from)
43
- response = execute_command('sendmsg', {
44
- :to => recipient,
45
- :text => message_text
46
- }.merge(auth_hash(auth_options)).merge(valid_options))
47
- parse_response(response)['ID']
48
- end
49
-
50
- # Returns the status of a message. Use message ID returned
51
- # from original send_message call. See send_message() for
52
- # auth_options.
53
- def message_status(message_id, auth_options)
54
- response = execute_command('querymsg', {
55
- :apimsgid => message_id
56
- }.merge( auth_hash(auth_options) ))
57
- parse_response(response)['Status']
58
- end
59
-
60
- # Returns the number of credits remaining as a float.
61
- # See send_message() for auth_options.
62
- def account_balance(auth_options)
63
- response = execute_command('getbalance', auth_hash(auth_options))
64
- parse_response(response)['Credit'].to_f
65
- end
66
-
67
- protected
68
- # Builds a command and sends it via HTTP GET.
69
- def execute_command(command_name, parameters)
70
- Net::HTTP.get_response(
71
- Command.new(command_name).with_params(parameters)
72
- )
73
- end
74
-
75
- def parse_response(raw_response) #:nodoc:
76
- Clickatell::Response.parse(raw_response)
77
- end
78
-
79
- def auth_hash(options) #:nodoc:
80
- if options[:session_id]
81
- return {
82
- :session_id => options[:session_id]
83
- }
84
- else
85
- return {
86
- :user => options[:username],
87
- :password => options[:password],
88
- :api_id => options[:api_key]
89
- }
90
- end
12
+ api = self.new
13
+ session_id = api.authenticate(api_id, username, password)
14
+ api.auth_options = { :session_id => session_id }
15
+ api
91
16
  end
92
17
 
18
+ # Set to true to enable debugging (off by default)
19
+ attr_accessor :debug_mode
93
20
  end
94
21
 
95
- # Represents a Clickatell HTTP gateway command in the form
96
- # of a complete URL (the raw, low-level request).
97
- class Command
98
- API_SERVICE_HOST = 'api.clickatell.com'
99
-
100
- def initialize(command_name, opts={})
101
- @command_name = command_name
102
- @options = { :secure => false }.merge(opts)
103
- end
104
-
105
- # Returns a URL for the given parameters (a hash).
106
- def with_params(param_hash)
107
- param_string = '?' + param_hash.map { |key, value| "#{key}=#{value}" }.sort.join('&')
108
- return URI.parse(File.join(api_service_uri, @command_name + URI.encode(param_string)))
109
- end
110
-
111
- protected
112
- def api_service_uri
113
- protocol = @options[:secure] ? 'https' : 'http'
114
- return "#{protocol}://#{API_SERVICE_HOST}/http/"
115
- end
22
+ # Creates a new API instance using the specified +auth options+.
23
+ # +auth_options+ is a hash containing either a :session_id or
24
+ # :username, :password and :api_key.
25
+ #
26
+ # Some API calls (authenticate, ping etc.) do not require any
27
+ # +auth_options+. +auth_options+ can be updated using the accessor methods.
28
+ def initialize(auth_options={})
29
+ @auth_options = auth_options
116
30
  end
117
31
 
118
- # Clickatell API Error exception.
119
- class Error < StandardError
120
- attr_reader :code, :message
121
-
122
- def initialize(code, message)
123
- @code, @message = code, message
124
- end
125
-
126
- # Creates a new Error from a Clickatell HTTP response string
127
- # e.g.:
128
- #
129
- # Error.parse("ERR: 001, Authentication error")
130
- # # => #<Clickatell::API::Error code='001' message='Authentication error'>
131
- def self.parse(error_string)
132
- error_details = error_string.split(':').last.strip
133
- code, message = error_details.split(',').map { |s| s.strip }
134
- self.new(code, message)
135
- end
32
+ # Authenticates using the specified credentials. Returns
33
+ # a session_id if successful which can be used in subsequent
34
+ # API calls.
35
+ def authenticate(api_id, username, password)
36
+ response = execute_command('auth',
37
+ :api_id => api_id,
38
+ :user => username,
39
+ :password => password
40
+ )
41
+ parse_response(response)['OK']
42
+ end
43
+
44
+ # Pings the service with the specified session_id to keep the
45
+ # session alive.
46
+ def ping(session_id)
47
+ execute_command('ping', :session_id => session_id)
48
+ end
49
+
50
+ # Sends a message +message_text+ to +recipient+. Recipient
51
+ # number should have an international dialing prefix and
52
+ # no leading zeros (unless you have set a default prefix
53
+ # in your clickatell account centre).
54
+ #
55
+ # Additional options:
56
+ # :from - the from number/name
57
+ #
58
+ # Returns a new message ID if successful.
59
+ def send_message(recipient, message_text, opts={})
60
+ valid_options = opts.only(:from)
61
+ response = execute_command('sendmsg',
62
+ {:to => recipient, :text => message_text}.merge(valid_options)
63
+ )
64
+ parse_response(response)['ID']
65
+ end
66
+
67
+ # Returns the status of a message. Use message ID returned
68
+ # from original send_message call.
69
+ def message_status(message_id)
70
+ response = execute_command('querymsg', :apimsgid => message_id)
71
+ parse_response(response)['Status']
136
72
  end
137
73
 
138
- class MessageStatus
139
- STATUS_MAP = {
140
- 1 => 'Message unknown',
141
- 2 => 'Message queued',
142
- 3 => 'Delivered to gateway',
143
- 4 => 'Received by recipient',
144
- 5 => 'Error with message',
145
- 6 => 'User cancelled messaged delivery',
146
- 7 => 'Error delivering message',
147
- 8 => 'OK',
148
- 9 => 'Routing error',
149
- 10 => 'Message expired',
150
- 11 => 'Message queued for later delivery',
151
- 12 => 'Out of credit'
152
- }
74
+ # Returns the number of credits remaining as a float.
75
+ def account_balance
76
+ response = execute_command('getbalance')
77
+ parse_response(response)['Credit'].to_f
78
+ end
79
+
80
+ protected
81
+ def execute_command(command_name, parameters={}) #:nodoc:
82
+ CommandExecutor.new(auth_hash, self.class.debug_mode).execute(command_name, parameters)
83
+ end
84
+
85
+ def parse_response(raw_response) #:nodoc:
86
+ Clickatell::Response.parse(raw_response)
87
+ end
153
88
 
154
- def self.[](code)
155
- STATUS_MAP[code]
89
+ def auth_hash #:nodoc:
90
+ if @auth_options[:session_id]
91
+ { :session_id => @auth_options[:session_id] }
92
+ elsif @auth_options[:api_id]
93
+ { :user => @auth_options[:username],
94
+ :password => @auth_options[:password],
95
+ :api_id => @auth_options[:api_key] }
96
+ else
97
+ {}
98
+ end
156
99
  end
157
- end
158
100
 
159
101
  end
102
+ end
103
+
104
+ %w( api/command
105
+ api/command_executor
106
+ api/error
107
+ api/message_status
108
+
109
+ ).each do |lib|
110
+ require File.join(File.dirname(__FILE__), lib)
160
111
  end
@@ -0,0 +1,28 @@
1
+ module Clickatell
2
+ class API
3
+
4
+ # Represents a Clickatell HTTP gateway command in the form
5
+ # of a complete URL (the raw, low-level request).
6
+ class Command
7
+ API_SERVICE_HOST = 'api.clickatell.com'
8
+
9
+ def initialize(command_name, opts={})
10
+ @command_name = command_name
11
+ @options = { :secure => false }.merge(opts)
12
+ end
13
+
14
+ # Returns a URL for the given parameters (a hash).
15
+ def with_params(param_hash)
16
+ param_string = '?' + param_hash.map { |key, value| "#{key}=#{value}" }.sort.join('&')
17
+ return URI.parse(File.join(api_service_uri, @command_name + URI.encode(param_string)))
18
+ end
19
+
20
+ protected
21
+ def api_service_uri
22
+ protocol = @options[:secure] ? 'https' : 'http'
23
+ return "#{protocol}://#{API_SERVICE_HOST}/http/"
24
+ end
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,31 @@
1
+ require 'net/http'
2
+
3
+ module Clickatell
4
+ class API
5
+
6
+ # Used to run commands agains the Clickatell gateway.
7
+ class CommandExecutor
8
+ def initialize(authentication_hash, debug=false)
9
+ @authentication_hash = authentication_hash
10
+ @debug = debug
11
+ end
12
+
13
+ # Builds a command object and sends it using HTTP GET.
14
+ # Will output URLs as they are requested to stdout when
15
+ # debugging is enabled.
16
+ def execute(command_name, parameters={})
17
+ request_uri = command(command_name, parameters)
18
+ puts "[debug] Sending request to #{request_uri}" if @debug
19
+ Net::HTTP.get_response(request_uri)
20
+ end
21
+
22
+ protected
23
+ def command(command_name, parameters) #:nodoc:
24
+ Command.new(command_name).with_params(
25
+ parameters.merge(@authentication_hash)
26
+ )
27
+ end
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,25 @@
1
+ module Clickatell
2
+ class API
3
+
4
+ # Clickatell API Error exception.
5
+ class Error < StandardError
6
+ attr_reader :code, :message
7
+
8
+ def initialize(code, message)
9
+ @code, @message = code, message
10
+ end
11
+
12
+ # Creates a new Error from a Clickatell HTTP response string
13
+ # e.g.:
14
+ #
15
+ # Error.parse("ERR: 001, Authentication error")
16
+ # # => #<Clickatell::API::Error code='001' message='Authentication error'>
17
+ def self.parse(error_string)
18
+ error_details = error_string.split(':').last.strip
19
+ code, message = error_details.split(',').map { |s| s.strip }
20
+ self.new(code, message)
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,26 @@
1
+ module Clickatell
2
+ class API
3
+
4
+ class MessageStatus
5
+ STATUS_MAP = {
6
+ 1 => 'Message unknown',
7
+ 2 => 'Message queued',
8
+ 3 => 'Delivered to gateway',
9
+ 4 => 'Received by recipient',
10
+ 5 => 'Error with message',
11
+ 6 => 'User cancelled messaged delivery',
12
+ 7 => 'Error delivering message',
13
+ 8 => 'OK',
14
+ 9 => 'Routing error',
15
+ 10 => 'Message expired',
16
+ 11 => 'Message queued for later delivery',
17
+ 12 => 'Out of credit'
18
+ }
19
+
20
+ def self.[](code)
21
+ STATUS_MAP[code]
22
+ end
23
+ end
24
+
25
+ end
26
+ end
@@ -43,6 +43,10 @@ module Clickatell
43
43
  @options.message_id = message_id
44
44
  @options.show_status = true
45
45
  end
46
+
47
+ opts.on('-d', '--debug') do
48
+ @options.debugging_enabled = true
49
+ end
46
50
 
47
51
  opts.on_tail('-h', '--help', "Show this message") do
48
52
  puts opts
@@ -1,7 +1,7 @@
1
1
  module Clickatell #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
- MINOR = 3
4
+ MINOR = 4
5
5
  TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
data/lib/core-ext/hash.rb CHANGED
@@ -7,7 +7,7 @@ class Hash
7
7
  #
8
8
  # Keys that do not exist in the original hash are ignored.
9
9
  def only(*keys)
10
- self.inject({}) do |new_hash, (key, value)|
10
+ inject( {} ) do |new_hash, (key, value)|
11
11
  new_hash[key] = value if keys.include?(key)
12
12
  new_hash
13
13
  end
data/spec/api_spec.rb CHANGED
@@ -31,120 +31,103 @@ module Clickatell
31
31
  end
32
32
 
33
33
  describe "Command executor" do
34
- it "should create an API command and send it via HTTP get, returning the raw http response" do
34
+ it "should create an API command with auth params and send it via HTTP get, returning the raw http response" do
35
+ executor = API::CommandExecutor.new(:session_id => '12345')
35
36
  API::Command.should_receive(:new).with('cmdname').and_return(cmd=mock('command'))
36
- cmd.should_receive(:with_params).with(:param_one => 'foo').and_return(uri=mock('uri'))
37
+ cmd.should_receive(:with_params).with(:param_one => 'foo', :session_id => '12345').and_return(uri=mock('uri'))
37
38
  Net::HTTP.should_receive(:get_response).with(uri).and_return(raw_response=mock('http response'))
38
- API.send(:execute_command, 'cmdname', :param_one => 'foo').should == raw_response
39
+ executor.execute('cmdname', :param_one => 'foo').should == raw_response
39
40
  end
40
41
  end
41
42
 
42
43
  describe "API" do
44
+ before do
45
+ API.debug_mode = false
46
+ API::CommandExecutor.should_receive(:new).with({:session_id => '1234'}, false).and_return(@executor = mock('command executor'))
47
+ @api = API.new(:session_id => '1234')
48
+ end
49
+
43
50
  it "should return session_id for successful authentication" do
44
- API.should_receive(:execute_command).with('auth',
51
+ @executor.should_receive(:execute).with('auth',
45
52
  :api_id => '1234',
46
53
  :user => 'joebloggs',
47
54
  :password => 'superpass'
48
55
  ).and_return(response=mock('response'))
49
56
  Response.should_receive(:parse).with(response).and_return('OK' => 'new_session_id')
50
- API.authenticate('1234', 'joebloggs', 'superpass').should == 'new_session_id'
57
+ @api.authenticate('1234', 'joebloggs', 'superpass').should == 'new_session_id'
51
58
  end
52
59
 
53
60
  it "should support ping" do
54
- API.should_receive(:execute_command).with('ping', :session_id => 'abcdefg').and_return(response=mock('response'))
55
- API.ping('abcdefg').should == response
61
+ @executor.should_receive(:execute).with('ping', :session_id => 'abcdefg').and_return(response=mock('response'))
62
+ @api.ping('abcdefg').should == response
56
63
  end
57
64
 
58
- it "should support sending messages with authentication, returning the message id" do
59
- API.should_receive(:execute_command).with('sendmsg',
60
- :api_id => '1234',
61
- :user => 'joebloggs',
62
- :password => 'superpass',
65
+ it "should support sending messages, returning the message id" do
66
+ @executor.should_receive(:execute).with('sendmsg',
63
67
  :to => '4477791234567',
64
68
  :text => 'hello world'
65
69
  ).and_return(response=mock('response'))
66
70
  Response.should_receive(:parse).with(response).and_return('ID' => 'message_id')
67
- API.send_message('4477791234567', 'hello world',
68
- :username => 'joebloggs', :password => 'superpass', :api_key => '1234'
69
- ).should == 'message_id'
70
- end
71
-
72
- it "should support sending messages with pre-auth, returning the message id" do
73
- API.should_receive(:execute_command).with('sendmsg',
74
- :session_id => 'abcde',
75
- :to => '4477791234567',
76
- :text => 'hello world'
77
- ).and_return(response=mock('response'))
78
- Response.should_receive(:parse).with(response).and_return('ID' => 'message_id')
79
- API.send_message('4477791234567', 'hello world', :session_id => 'abcde').should == 'message_id'
71
+ @api.send_message('4477791234567', 'hello world').should == 'message_id'
80
72
  end
81
73
 
82
74
  it "should support sending messages with custom from number, returning the message id" do
83
- API.should_receive(:execute_command).with('sendmsg',
84
- :session_id => 'abcde',
75
+ @executor.should_receive(:execute).with('sendmsg',
85
76
  :to => '4477791234567',
86
77
  :text => 'hello world',
87
78
  :from => 'LUKE'
88
79
  ).and_return(response=mock('response'))
89
80
  Response.should_receive(:parse).with(response).and_return('ID' => 'message_id')
90
- API.send_message('4477791234567', 'hello world', {:session_id => 'abcde'}, :from => 'LUKE')
81
+ @api.send_message('4477791234567', 'hello world', :from => 'LUKE')
91
82
  end
92
83
 
93
84
  it "should ignore any invalid parameters when sending message" do
94
- API.should_receive(:execute_command).with('sendmsg',
95
- :session_id => 'abcde',
85
+ @executor.should_receive(:execute).with('sendmsg',
96
86
  :to => '4477791234567',
97
87
  :text => 'hello world',
98
88
  :from => 'LUKE'
99
89
  ).and_return(response=mock('response'))
100
90
  Response.stub!(:parse).and_return('ID' => 'foo')
101
- API.send_message('4477791234567', 'hello world', {:session_id => 'abcde'}, :from => 'LUKE', :any_old_param => 'test')
91
+ @api.send_message('4477791234567', 'hello world', :from => 'LUKE', :any_old_param => 'test')
102
92
  end
103
93
 
104
- it "should support message status query with authentication, returning message status" do
105
- API.should_receive(:execute_command).with('querymsg',
106
- :api_id => '1234',
107
- :user => 'joebloggs',
108
- :password => 'superpass',
109
- :apimsgid => 'messageid'
110
- ).and_return(response=mock('response'))
111
- Response.should_receive(:parse).with(response).and_return('ID' => 'message_id', 'Status' => 'message_status')
112
- API.message_status('messageid',
113
- :username => 'joebloggs', :password => 'superpass', :api_key => '1234'
114
- ).should == 'message_status'
115
- end
116
-
117
- it "should support message status query with pre-auth" do
118
- API.should_receive(:execute_command).with('querymsg',
119
- :session_id => 'abcde',
94
+ it "should support message status query, returning message status" do
95
+ @executor.should_receive(:execute).with('querymsg',
120
96
  :apimsgid => 'messageid'
121
97
  ).and_return(response=mock('response'))
122
98
  Response.should_receive(:parse).with(response).and_return('ID' => 'message_id', 'Status' => 'message_status')
123
- API.message_status('messageid', :session_id => 'abcde').should == 'message_status'
99
+ @api.message_status('messageid').should == 'message_status'
124
100
  end
125
101
 
126
- it "should support balance query with authentication, returning number of credits as a float" do
127
- API.should_receive(:execute_command).with('getbalance',
128
- :api_id => '1234',
129
- :user => 'joebloggs',
130
- :password => 'superpass'
131
- ).and_return(response=mock('response'))
102
+ it "should support balance query, returning number of credits as a float" do
103
+ @executor.should_receive(:execute).with('getbalance', {}).and_return(response=mock('response'))
132
104
  Response.should_receive(:parse).with(response).and_return('Credit' => '10.0')
133
- API.account_balance(:username => 'joebloggs', :password => 'superpass', :api_key => '1234').should == 10.0
134
- end
135
-
136
- it "should support balance query with pre-auth, returning number of credits as a float" do
137
- API.should_receive(:execute_command).with('getbalance',
138
- :session_id => 'abcde'
139
- ).and_return(response=mock('response'))
140
- Response.should_receive(:parse).with(response).and_return('Credit' => '10.0')
141
- API.account_balance(:session_id => 'abcde').should == 10.0
105
+ @api.account_balance.should == 10.0
142
106
  end
143
107
 
144
108
  it "should raise an API::Error if the response parser raises" do
145
- API.stub!(:execute_command)
109
+ @executor.stub!(:execute)
146
110
  Response.stub!(:parse).and_raise(Clickatell::API::Error.new('', ''))
147
- proc { API.account_balance({}) }.should raise_error(Clickatell::API::Error)
111
+ proc { @api.account_balance }.should raise_error(Clickatell::API::Error)
112
+ end
113
+ end
114
+
115
+ describe API, ' when authenticating' do
116
+ it "should authenticate to retrieve a session_id and return a new API instance using that session id" do
117
+ API.stub!(:new).and_return(api=mock('api'))
118
+ api.should_receive(:authenticate).with('my_api_key', 'joebloggs', 'mypassword').and_return('new_session_id')
119
+ api.should_receive(:auth_options=).with(:session_id => 'new_session_id')
120
+ API.authenticate('my_api_key', 'joebloggs', 'mypassword')
121
+ end
122
+ end
123
+
124
+ describe API, ' with no authentication options set' do
125
+ it "should build commands with no authentication options" do
126
+ API.debug_mode = false
127
+ api = API.new
128
+ API::CommandExecutor.should_receive(:new).with({}, false).and_return(executor=mock('command executor'))
129
+ executor.stub!(:execute)
130
+ api.ping('1234')
148
131
  end
149
132
  end
150
133
 
data/website/index.txt CHANGED
@@ -29,11 +29,17 @@ account username and password.
29
29
  require 'rubygems'
30
30
  require 'clickatell'
31
31
 
32
- connection = Clickatell::Connection.new('your_api_id', 'your_username', 'your_password')
33
- connection.send_message('447771234567', 'Hello from clickatell')
32
+ api = Clickatell::API.authenticate('your_api_id', 'your_username', 'your_password')
33
+ api.send_message('447771234567', 'Hello from clickatell')
34
34
  </code></pre>
35
35
 
36
36
  Full documentation for the API is available in the <a href="rdoc/">RDocs</a>.
37
+
38
+ For debugging purposes, the API allows you to view gateway URIs as they are requested, printed to $stdout. You can enable this by turning on +debug_mode+.
39
+
40
+ <pre><code class="ruby">
41
+ Clickatell::API.debug_mode = true
42
+ </code></pre>
37
43
 
38
44
  h4. Command-line SMS Utility
39
45
 
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: clickatell
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.3.0
7
- date: 2007-08-23 00:00:00 +01:00
6
+ version: 0.4.0
7
+ date: 2007-08-29 00:00:00 +01:00
8
8
  summary: Ruby interface to the Clickatell SMS gateway service.
9
9
  require_paths:
10
10
  - lib
@@ -37,7 +37,10 @@ files:
37
37
  - bin/sms
38
38
  - lib/clickatell.rb
39
39
  - lib/clickatell/api.rb
40
- - lib/clickatell/connection.rb
40
+ - lib/clickatell/api/command.rb
41
+ - lib/clickatell/api/command_executor.rb
42
+ - lib/clickatell/api/error.rb
43
+ - lib/clickatell/api/message_status.rb
41
44
  - lib/clickatell/response.rb
42
45
  - lib/clickatell/utility.rb
43
46
  - lib/clickatell/utility/options.rb
@@ -46,7 +49,6 @@ files:
46
49
  - scripts/txt2html
47
50
  - setup.rb
48
51
  - spec/api_spec.rb
49
- - spec/connection_spec.rb
50
52
  - spec/hash_ext_spec.rb
51
53
  - spec/response_spec.rb
52
54
  - spec/spec.opts
@@ -1,62 +0,0 @@
1
- module Clickatell
2
-
3
- # The Connection object provides a high-level interface to the
4
- # Clickatell API, handling authentication across multiple API
5
- # requests.
6
- #
7
- # Example:
8
- # conn = Clickatell::Connection.new('your_api_key', 'joebloggs', 'secret')
9
- # message_id = conn.send_message('44777123456', 'This is a test message')
10
- # status = conn.message_status(message_id)
11
- #
12
- # The Connection object provides all of the public methods implemented in
13
- # Clickatell::API but handles the passing of authentication options
14
- # automatically so it is not required to pass any authentication_option hashes
15
- # into API methods that require them.
16
- class Connection
17
-
18
- # Returns the current Clickatell session ID.
19
- attr_reader :session_id
20
-
21
- # +api_key+: Your Clickatell API ID/key.
22
- # +username+: Your Clickatell account username.
23
- # +password+: Your Clickatell account password.
24
- def initialize(api_key, username, password)
25
- @api_key = api_key
26
- @username = username
27
- @password = password
28
- end
29
-
30
- # Manual authentication. Will create a new Clickatell session
31
- # and store the session ID.
32
- def authenticate!
33
- @session_id = API.authenticate(@api_key, @username, @password)
34
- end
35
-
36
- protected
37
- # Executes the given +api_method+ by delegating to the API
38
- # module, using the current session_id for authentication.
39
- def execute_api_call(api_method, params, additional_options)
40
- params << {:session_id => current_session_id}
41
- params << additional_options if additional_options
42
- API.send(api_method, *params)
43
- end
44
-
45
- # Returns the current_session_id, authenticating if one doesn't exist
46
- def current_session_id
47
- authenticate! if session_id.nil?
48
- session_id
49
- end
50
-
51
- # Dispatch any API methods to the API module.
52
- def method_missing(method, *args, &block)
53
- if API.respond_to?(method)
54
- additional_options = args.pop if args.last.is_a?(Hash)
55
- execute_api_call(method, args, additional_options)
56
- else
57
- super(method, args, &block)
58
- end
59
- end
60
- end
61
-
62
- end
@@ -1,33 +0,0 @@
1
- require File.dirname(__FILE__) + '/spec_helper'
2
- require File.dirname(__FILE__) + '/../lib/clickatell'
3
-
4
- module Clickatell
5
-
6
- describe Connection, ' when unauthenticated' do
7
- it "should authenticate and store session_id before sending command" do
8
- connection = Connection.new('my_api_key', 'myusername', 'mypassword')
9
- API.should_receive(:authenticate).with('my_api_key', 'myusername', 'mypassword').and_return('new_session_id')
10
- API.should_receive(:send_message).with('4477791234567', 'hello world', :session_id => 'new_session_id')
11
- connection.send_message('4477791234567', 'hello world')
12
- end
13
- end
14
-
15
- describe Connection, ' when authenticated' do
16
- before do
17
- @connection = Connection.new('my_api_key', 'myusername', 'mypassword')
18
- @connection.stub!(:session_id).and_return('session_id')
19
- end
20
-
21
- it "should send command with session_id without re-authenticating" do
22
- API.should_receive(:authenticate).never
23
- API.should_receive(:send_message).with('4477791234567', 'hello world', :session_id => 'session_id')
24
- @connection.send_message('4477791234567', 'hello world')
25
- end
26
-
27
- it "should support API calls with additional opts, passing them after auth options" do
28
- API.should_receive(:send_message).with('4477791234567', 'hello world', {:session_id => 'session_id'}, :from => 'LUKE')
29
- @connection.send_message('4477791234567', 'hello world', {:from => 'LUKE'})
30
- end
31
- end
32
-
33
- end