clickatell 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,98 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require File.dirname(__FILE__) + '/../lib/clickatell'
3
+
4
+ module Clickatell
5
+
6
+ describe "API Command" do
7
+ it "should return encoded URL for the specified command and parameters" do
8
+ command = API::Command.new('cmdname')
9
+ url = command.with_params(:param_one => 'abc', :param_two => '123')
10
+ url.should == URI.parse("http://api.clickatell.com/http/cmdname?param_one=abc&param_two=123")
11
+ end
12
+
13
+ it "should URL encode any special characters in parameters" do
14
+ command = API::Command.new('cmdname')
15
+ url = command.with_params(:param_one => 'abc', :param_two => 'hello world')
16
+ url.should == URI.parse("http://api.clickatell.com/http/cmdname?param_one=abc&param_two=hello%20world")
17
+ end
18
+
19
+ it "should support non-secure api commands" do
20
+ command = API::Command.new('cmdname', :secure => true)
21
+ url = command.with_params(:param_one => 'abc', :param_two => '123')
22
+ url.should == URI.parse("https://api.clickatell.com/http/cmdname?param_one=abc&param_two=123")
23
+ end
24
+ end
25
+
26
+ describe "Command executor" do
27
+ it "should create an API command and send it via HTTP get" do
28
+ API::Command.should_receive(:new).with('cmdname').and_return(cmd=mock('command'))
29
+ cmd.should_receive(:with_params).with(:param_one => 'foo').and_return(uri=mock('uri'))
30
+ Net::HTTP.should_receive(:get_response).with(uri).and_return(raw_response=mock('http response'))
31
+ API.send(:execute_command, 'cmdname', :param_one => 'foo').should == raw_response
32
+ end
33
+ end
34
+
35
+ describe "API" do
36
+ it "should return session_id for successful authentication" do
37
+ API.should_receive(:execute_command).with('auth',
38
+ :api_id => '1234',
39
+ :user => 'joebloggs',
40
+ :password => 'superpass'
41
+ ).and_return(response=mock('response'))
42
+ Response.should_receive(:parse).with(response).and_return('OK' => 'new_session_id')
43
+ API.authenticate('1234', 'joebloggs', 'superpass').should == 'new_session_id'
44
+ end
45
+
46
+ it "should support ping" do
47
+ API.should_receive(:execute_command).with('ping', :session_id => 'abcdefg').and_return(response=mock('response'))
48
+ API.ping('abcdefg').should == response
49
+ end
50
+
51
+ it "should support sending messages with authentication, returning the message id" do
52
+ API.should_receive(:execute_command).with('sendmsg',
53
+ :api_id => '1234',
54
+ :user => 'joebloggs',
55
+ :password => 'superpass',
56
+ :to => '4477791234567',
57
+ :text => 'hello world'
58
+ ).and_return(response=mock('response'))
59
+ Response.should_receive(:parse).with(response).and_return('ID' => 'message_id')
60
+ API.send_message('4477791234567', 'hello world',
61
+ :username => 'joebloggs', :password => 'superpass', :api_key => '1234'
62
+ ).should == 'message_id'
63
+ end
64
+
65
+ it "should support sending messages with pre-auth, returning the message id" do
66
+ API.should_receive(:execute_command).with('sendmsg',
67
+ :session_id => 'abcde',
68
+ :to => '4477791234567',
69
+ :text => 'hello world'
70
+ ).and_return(response=mock('response'))
71
+ Response.should_receive(:parse).with(response).and_return('ID' => 'message_id')
72
+ API.send_message('4477791234567', 'hello world', :session_id => 'abcde').should == 'message_id'
73
+ end
74
+
75
+ it "should support message status query with authentication, returning message status" do
76
+ API.should_receive(:execute_command).with('querymsg',
77
+ :api_id => '1234',
78
+ :user => 'joebloggs',
79
+ :password => 'superpass',
80
+ :apimsgid => 'messageid'
81
+ ).and_return(response=mock('response'))
82
+ Response.should_receive(:parse).with(response).and_return('ID' => 'message_id', 'Status' => 'message_status')
83
+ API.message_status('messageid',
84
+ :username => 'joebloggs', :password => 'superpass', :api_key => '1234'
85
+ ).should == 'message_status'
86
+ end
87
+
88
+ it "should support message status query with pre-auth" do
89
+ API.should_receive(:execute_command).with('querymsg',
90
+ :session_id => 'abcde',
91
+ :apimsgid => 'messageid'
92
+ ).and_return(response=mock('response'))
93
+ Response.should_receive(:parse).with(response).and_return('ID' => 'message_id', 'Status' => 'message_status')
94
+ API.message_status('messageid', :session_id => 'abcde').should == 'message_status'
95
+ end
96
+ end
97
+
98
+ end
@@ -0,0 +1,25 @@
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
+ it "should send command with session_id without re-authenticating" do
17
+ connection = Connection.new('my_api_key', 'myusername', 'mypassword')
18
+ connection.stub!(:session_id).and_return('session_id')
19
+ API.should_receive(:authenticate).never
20
+ API.should_receive(:send_message).with('4477791234567', 'hello world', :session_id => 'session_id')
21
+ connection.send_message('4477791234567', 'hello world')
22
+ end
23
+ end
24
+
25
+ end
@@ -0,0 +1,14 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require File.dirname(__FILE__) + '/../lib/clickatell'
3
+
4
+ module Clickatell
5
+
6
+ describe "Response parser" do
7
+ it "should return hash for one-line success response" do
8
+ raw_response = stub('response')
9
+ raw_response.stub!(:body).and_return('k1: foo k2: bar')
10
+ Response.parse(raw_response).should == {'k1' => 'foo', 'k2' => 'bar'}
11
+ end
12
+ end
13
+
14
+ end
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,2 @@
1
+ require 'rubygems'
2
+ require 'spec'
@@ -0,0 +1,111 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head>
5
+ <link rel="stylesheet" href="stylesheets/screen.css" type="text/css" media="screen" />
6
+ <link rel="stylesheet" href="stylesheets/limechoc.css" type="text/css" media="screen" />
7
+ <script type="text/javascript" charset="utf-8" src="javascripts/codehighlighter/code_highlighter.js"></script>
8
+ <script type="text/javascript" charset="utf-8" src="javascripts/codehighlighter/ruby.js"></script>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
10
+ <title>Clickatell Ruby API</title>
11
+ </head>
12
+ <body>
13
+
14
+ <div id="wrapper">
15
+ <div id="container">
16
+
17
+ <div id="header">
18
+
19
+ <h1>Clickatell Ruby API 0.1.0
20
+ <span class="tagline">gem install clickatell</span></h1>
21
+
22
+ </div>
23
+
24
+ <div id="content">
25
+ <div class="article"><h3>What is it?</h3>
26
+
27
+
28
+ <p>A Ruby interface to the <a href="http://www.clickatell.com">Clickatell</a> SMS gateway <span class="caps">API</span>.</p>
29
+
30
+
31
+ <h3>Installing</h3>
32
+
33
+
34
+ <p>Download the <a href="http://rubyforge.org/projects/clickatell">latest version of gem</a> or install using RubyGems</p>
35
+
36
+ <pre><code>$ sudo gem install clickatell</code></pre>
37
+
38
+ <h3>The basics</h3>
39
+
40
+
41
+ <p>To use this gem, you will need sign up for an account at <a href="http://www.clickatell.com">the Clickatell website</a>.
42
+ Once you are registered and logged into your account centre, you should add
43
+ an <span class="caps">HTTP API</span> connection to your account. This will give you your <span class="caps">API</span>_ID.</p>
44
+
45
+
46
+ <h3>Demonstration of usage</h3>
47
+
48
+
49
+ <p>You can now use the library directly. You will need your <span class="caps">API</span>_ID as well as your
50
+ account username and password.</p>
51
+
52
+
53
+ <pre><code class="ruby">
54
+ require 'rubygems'
55
+ require 'clickatell'
56
+
57
+ connection = Clickatell::Connection.new('your_api_id', 'your_username', 'your_password')
58
+ connection.send_message('447771234567', 'Hello from clickatell')
59
+ </code></pre>
60
+
61
+ <h4>Command-line <span class="caps">SMS</span> Utility</h4>
62
+
63
+
64
+ <p>The Clickatell gem also comes with a command-line utility that will allow you
65
+ to send an <span class="caps">SMS</span> directly from the command-line.</p>
66
+
67
+
68
+ <p>You will need to create a <span class="caps">YAML</span> configuration file in your home directory, in a
69
+ file called .clickatell that resembles the following:</p>
70
+
71
+
72
+ <pre><code>
73
+ # ~/.clickatell
74
+ api_key: your_api_id
75
+ username: your_username
76
+ password: your_password
77
+ </code></pre>
78
+
79
+ <p>You can then use the sms utility to send a message to a single recipient:</p>
80
+
81
+
82
+ <pre><code>
83
+ $ sms 447771234567 'Hello from clickatell'
84
+ </code></pre>
85
+
86
+ <h3>License</h3>
87
+
88
+
89
+ <p>This code is free to use under the terms of the <span class="caps">MIT</span> license.</p>
90
+
91
+
92
+ <h3>Contact</h3>
93
+
94
+
95
+ <p>Comments are welcome. Send an email to <a href="mailto:contact@lukeredpath.co.uk">Luke Redpath</a> email.</p></div>
96
+ </div>
97
+
98
+ </div>
99
+
100
+ <div id="footer_wrapper">
101
+ <div id="footer">
102
+ <p class="copyright">
103
+ <a href="http://rubyforge.org/projects/clickatell">Rubyforge Project Page</a> |
104
+ <a href="http://rubyforge.org/projects/clickatell">Download latest version (0.1.0)</a>
105
+ </p>
106
+ </div>
107
+ </div>
108
+ </div>
109
+
110
+ </body>
111
+ </html>
@@ -0,0 +1,59 @@
1
+ h1. Clickatell Ruby API
2
+
3
+ h3. What is it?
4
+
5
+ A Ruby interface to the "Clickatell":http://www.clickatell.com SMS gateway API.
6
+
7
+ h3. Installing
8
+
9
+ <p>Download the <a href="http://rubyforge.org/projects/clickatell">latest version of gem</a> or install using RubyGems</p>
10
+
11
+ <pre><code>$ sudo gem install clickatell</code></pre>
12
+
13
+ h3. The basics
14
+
15
+ To use this gem, you will need sign up for an account at "the Clickatell website":http://www.clickatell.com.
16
+ Once you are registered and logged into your account centre, you should add
17
+ an HTTP API connection to your account. This will give you your API_ID.
18
+
19
+ h3. Demonstration of usage
20
+
21
+ You can now use the library directly. You will need your API_ID as well as your
22
+ account username and password.
23
+
24
+ <pre><code class="ruby">
25
+ require 'rubygems'
26
+ require 'clickatell'
27
+
28
+ connection = Clickatell::Connection.new('your_api_id', 'your_username', 'your_password')
29
+ connection.send_message('447771234567', 'Hello from clickatell')
30
+ </code></pre>
31
+
32
+ h4. Command-line SMS Utility
33
+
34
+ The Clickatell gem also comes with a command-line utility that will allow you
35
+ to send an SMS directly from the command-line.
36
+
37
+ You will need to create a YAML configuration file in your home directory, in a
38
+ file called .clickatell that resembles the following:
39
+
40
+ <pre><code>
41
+ # ~/.clickatell
42
+ api_key: your_api_id
43
+ username: your_username
44
+ password: your_password
45
+ </code></pre>
46
+
47
+ You can then use the sms utility to send a message to a single recipient:
48
+
49
+ <pre><code>
50
+ $ sms 447771234567 'Hello from clickatell'
51
+ </code></pre>
52
+
53
+ h3. License
54
+
55
+ This code is free to use under the terms of the MIT license.
56
+
57
+ h3. Contact
58
+
59
+ Comments are welcome. Send an email to "Luke Redpath":mailto:contact@lukeredpath.co.uk email.
@@ -0,0 +1,188 @@
1
+ /* Unobtrustive Code Highlighter By Dan Webb 11/2005
2
+ Version: 0.4
3
+
4
+ Usage:
5
+ Add a script tag for this script and any stylesets you need to use
6
+ to the page in question, add correct class names to CODE elements,
7
+ define CSS styles for elements. That's it!
8
+
9
+ Known to work on:
10
+ IE 5.5+ PC
11
+ Firefox/Mozilla PC/Mac
12
+ Opera 7.23 + PC
13
+ Safari 2
14
+
15
+ Known to degrade gracefully on:
16
+ IE5.0 PC
17
+
18
+ Note: IE5.0 fails due to the use of lookahead in some stylesets. To avoid script errors
19
+ in older browsers use expressions that use lookahead in string format when defining stylesets.
20
+
21
+ This script is inspired by star-light by entirely cunning Dean Edwards
22
+ http://dean.edwards.name/star-light/.
23
+ */
24
+
25
+ // replace callback support for safari.
26
+ if ("a".replace(/a/, function() {return "b"}) != "b") (function(){
27
+ var default_replace = String.prototype.replace;
28
+ String.prototype.replace = function(search,replace){
29
+ // replace is not function
30
+ if(typeof replace != "function"){
31
+ return default_replace.apply(this,arguments)
32
+ }
33
+ var str = "" + this;
34
+ var callback = replace;
35
+ // search string is not RegExp
36
+ if(!(search instanceof RegExp)){
37
+ var idx = str.indexOf(search);
38
+ return (
39
+ idx == -1 ? str :
40
+ default_replace.apply(str,[search,callback(search, idx, str)])
41
+ )
42
+ }
43
+ var reg = search;
44
+ var result = [];
45
+ var lastidx = reg.lastIndex;
46
+ var re;
47
+ while((re = reg.exec(str)) != null){
48
+ var idx = re.index;
49
+ var args = re.concat(idx, str);
50
+ result.push(
51
+ str.slice(lastidx,idx),
52
+ callback.apply(null,args).toString()
53
+ );
54
+ if(!reg.global){
55
+ lastidx += RegExp.lastMatch.length;
56
+ break
57
+ }else{
58
+ lastidx = reg.lastIndex;
59
+ }
60
+ }
61
+ result.push(str.slice(lastidx));
62
+ return result.join("")
63
+ }
64
+ })();
65
+
66
+ var CodeHighlighter = { styleSets : new Array };
67
+
68
+ CodeHighlighter.addStyle = function(name, rules) {
69
+ // using push test to disallow older browsers from adding styleSets
70
+ if ([].push) this.styleSets.push({
71
+ name : name,
72
+ rules : rules,
73
+ ignoreCase : arguments[2] || false
74
+ })
75
+
76
+ function setEvent() {
77
+ // set highlighter to run on load (use LowPro if present)
78
+ if (typeof Event != 'undefined' && typeof Event.onReady == 'function')
79
+ return Event.onReady(CodeHighlighter.init.bind(CodeHighlighter));
80
+
81
+ var old = window.onload;
82
+
83
+ if (typeof window.onload != 'function') {
84
+ window.onload = function() { CodeHighlighter.init() };
85
+ } else {
86
+ window.onload = function() {
87
+ old();
88
+ CodeHighlighter.init();
89
+ }
90
+ }
91
+ }
92
+
93
+ // only set the event when the first style is added
94
+ if (this.styleSets.length==1) setEvent();
95
+ }
96
+
97
+ CodeHighlighter.init = function() {
98
+ if (!document.getElementsByTagName) return;
99
+ if ("a".replace(/a/, function() {return "b"}) != "b") return; // throw out Safari versions that don't support replace function
100
+ // throw out older browsers
101
+
102
+ var codeEls = document.getElementsByTagName("CODE");
103
+ // collect array of all pre elements
104
+ codeEls.filter = function(f) {
105
+ var a = new Array;
106
+ for (var i = 0; i < this.length; i++) if (f(this[i])) a[a.length] = this[i];
107
+ return a;
108
+ }
109
+
110
+ var rules = new Array;
111
+ rules.toString = function() {
112
+ // joins regexes into one big parallel regex
113
+ var exps = new Array;
114
+ for (var i = 0; i < this.length; i++) exps.push(this[i].exp);
115
+ return exps.join("|");
116
+ }
117
+
118
+ function addRule(className, rule) {
119
+ // add a replace rule
120
+ var exp = (typeof rule.exp != "string")?String(rule.exp).substr(1, String(rule.exp).length-2):rule.exp;
121
+ // converts regex rules to strings and chops of the slashes
122
+ rules.push({
123
+ className : className,
124
+ exp : "(" + exp + ")",
125
+ length : (exp.match(/(^|[^\\])\([^?]/g) || "").length + 1, // number of subexps in rule
126
+ replacement : rule.replacement || null
127
+ });
128
+ }
129
+
130
+ function parse(text, ignoreCase) {
131
+ // main text parsing and replacement
132
+ return text.replace(new RegExp(rules, (ignoreCase)?"gi":"g"), function() {
133
+ var i = 0, j = 1, rule;
134
+ while (rule = rules[i++]) {
135
+ if (arguments[j]) {
136
+ // if no custom replacement defined do the simple replacement
137
+ if (!rule.replacement) return "<span class=\"" + rule.className + "\">" + arguments[0] + "</span>";
138
+ else {
139
+ // replace $0 with the className then do normal replaces
140
+ var str = rule.replacement.replace("$0", rule.className);
141
+ for (var k = 1; k <= rule.length - 1; k++) str = str.replace("$" + k, arguments[j + k]);
142
+ return str;
143
+ }
144
+ } else j+= rule.length;
145
+ }
146
+ });
147
+ }
148
+
149
+ function highlightCode(styleSet) {
150
+ // clear rules array
151
+ var parsed, clsRx = new RegExp("(\\s|^)" + styleSet.name + "(\\s|$)");
152
+ rules.length = 0;
153
+
154
+ // get stylable elements by filtering out all code elements without the correct className
155
+ var stylableEls = codeEls.filter(function(item) { return clsRx.test(item.className) });
156
+
157
+ // add style rules to parser
158
+ for (var className in styleSet.rules) addRule(className, styleSet.rules[className]);
159
+
160
+
161
+ // replace for all elements
162
+ for (var i = 0; i < stylableEls.length; i++) {
163
+ // EVIL hack to fix IE whitespace badness if it's inside a <pre>
164
+ if (/MSIE/.test(navigator.appVersion) && stylableEls[i].parentNode.nodeName == 'PRE') {
165
+ stylableEls[i] = stylableEls[i].parentNode;
166
+
167
+ parsed = stylableEls[i].innerHTML.replace(/(<code[^>]*>)([^<]*)<\/code>/i, function() {
168
+ return arguments[1] + parse(arguments[2], styleSet.ignoreCase) + "</code>"
169
+ });
170
+ parsed = parsed.replace(/\n( *)/g, function() {
171
+ var spaces = "";
172
+ for (var i = 0; i < arguments[1].length; i++) spaces+= "&nbsp;";
173
+ return "\n" + spaces;
174
+ });
175
+ parsed = parsed.replace(/\t/g, "&nbsp;&nbsp;&nbsp;&nbsp;");
176
+ parsed = parsed.replace(/\n(<\/\w+>)?/g, "<br />$1").replace(/<br \/>[\n\r\s]*<br \/>/g, "<p><br></p>");
177
+
178
+ } else parsed = parse(stylableEls[i].innerHTML, styleSet.ignoreCase);
179
+
180
+ stylableEls[i].innerHTML = parsed;
181
+ }
182
+ }
183
+
184
+ // run highlighter on all stylesets
185
+ for (var i=0; i < this.styleSets.length; i++) {
186
+ highlightCode(this.styleSets[i]);
187
+ }
188
+ }