google_text 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CONTRIBUTORS +1 -0
- data/HISTORY.md +3 -0
- data/LICENSE +20 -0
- data/README.md +90 -0
- data/Rakefile +21 -0
- data/VERSION +1 -0
- data/lib/google_text.rb +9 -0
- data/lib/google_text/account.rb +9 -0
- data/lib/google_text/client.rb +114 -0
- data/lib/google_text/configuration.rb +46 -0
- data/lib/google_text/message.rb +57 -0
- data/lib/google_text/parser.rb +107 -0
- data/lib/google_text/session.rb +51 -0
- data/lib/google_text/version.rb +3 -0
- data/spec/google-text/client_spec.rb +90 -0
- data/spec/google-text/configuration_spec.rb +37 -0
- data/spec/google-text/message_spec.rb +39 -0
- data/spec/spec_helper.rb +5 -0
- metadata +130 -0
data/CONTRIBUTORS
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Sebastian Friedrich
|
data/HISTORY.md
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Sebastian Friedrich
|
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 PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL 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.
|
data/README.md
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
GoogleText
|
2
|
+
=========
|
3
|
+
|
4
|
+
GoogleText is a SMS client library for sending and receiving free SMS through Google Voice.
|
5
|
+
|
6
|
+
For more information visit
|
7
|
+
<http://google_text.github.com/>.
|
8
|
+
|
9
|
+
|
10
|
+
Overview
|
11
|
+
--------
|
12
|
+
|
13
|
+
GoogleText is a SMS client library for sending and receiving free SMS through Google Voice. Alas, Google Voice does not yet have an API. So GoogleText uses Curl and Nokogiri to scrape and post using your regular Google Voice service URLs.
|
14
|
+
|
15
|
+
|
16
|
+
Why?
|
17
|
+
----
|
18
|
+
|
19
|
+
Sure, there are a bunch of SMS implementations out there. And while GoogleText is pretty slow and perhaps a bit fragile it is also _absolutely free_ and allows both sending and receiving to and from a real free phone number. Pretty great, if you ask me, and worth the tradeoff in performance.
|
20
|
+
|
21
|
+
|
22
|
+
Prerequisites
|
23
|
+
-------------
|
24
|
+
|
25
|
+
GoogleText currently relies on the following gems:
|
26
|
+
|
27
|
+
* nokogiri
|
28
|
+
* curb
|
29
|
+
* json
|
30
|
+
|
31
|
+
Installation
|
32
|
+
------------
|
33
|
+
|
34
|
+
1. Get a Google Voice account, if don't already have one
|
35
|
+
|
36
|
+
2. Install the gem, which should also install all the perquisites.
|
37
|
+
|
38
|
+
`gem install google_text`
|
39
|
+
|
40
|
+
3. Configure GoogleText someplace sensible, using the email address and password you use to log on to your Google Voice account. If you are using GoogleText in a Rails application, `config/initializers/google_text.rb` is a good place to put the configuration block:
|
41
|
+
|
42
|
+
|
43
|
+
Sample Configuration:
|
44
|
+
|
45
|
+
GoogleText.configure do |config|
|
46
|
+
config.email = 'google-user'
|
47
|
+
config.password = 'google-password'
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
Usage
|
52
|
+
-----
|
53
|
+
|
54
|
+
Setup:
|
55
|
+
|
56
|
+
>> require 'rubygems'
|
57
|
+
=> false
|
58
|
+
>> require 'google_text'
|
59
|
+
=> true
|
60
|
+
>> GoogleText.configure {|config| config.email, config.password = 'google-user', 'google-password'}
|
61
|
+
=> ["google-user", "google-password"]
|
62
|
+
|
63
|
+
Sending a message:
|
64
|
+
|
65
|
+
>> message = GoogleText::Message.new(:text => "Hello World!", :to => "(311) 615-4156")
|
66
|
+
=> #<GoogleText::Message:0x102503630 @text="Hello World!", @to="3116154156">
|
67
|
+
>> message.send
|
68
|
+
=> #<GoogleText::Message:0x102515240 @to="3116154156", @sent_status=true, @text="Hello World!">
|
69
|
+
>> message.sent?
|
70
|
+
=> true
|
71
|
+
|
72
|
+
Receiving unread messages:
|
73
|
+
|
74
|
+
>> messages = GoogleText::Message.unread
|
75
|
+
=> [#<GoogleText::Message:0x1023fda38 @display_number="+3116154156", @from="(650) 265-1193", @read_status=false, @id="f298c576522c6a1ecc976c649e9826c31e017a24", @relative_start_time="3 minutes ago", @to="Me", @display_start_date_time="6/16/10 2:57 AM", @display_start_time="2:57 AM", @text="Hello World", @labels=["inbox", "unread", "sms", "all"], @start_time=1276671459139>]
|
76
|
+
>> message = messages.first
|
77
|
+
=> #<GoogleText::Message>
|
78
|
+
>> message.read?
|
79
|
+
=> false
|
80
|
+
>> message.mark_as_read
|
81
|
+
=> #<GoogleText::Message>
|
82
|
+
=> message.read?
|
83
|
+
=> true
|
84
|
+
>> messages = GoogleText::Message.unread
|
85
|
+
=> []
|
86
|
+
|
87
|
+
Acknowledgements
|
88
|
+
---------------
|
89
|
+
|
90
|
+
Many thanks to [kgautreaux](http://github.com/kgautreaux). I copied most of the code used for scraping and posting the Google Voice pages from [gvoice-ruby](http://github.com/kgautreaux/gvoice-ruby). His work was an enormous help in getting this gem done very quickly, as I'm sure reverse-engineering this took quite a bit of time and effort.
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
require 'rake/rdoctask'
|
3
|
+
|
4
|
+
desc "Push a new version to Rubygems."
|
5
|
+
task :publish do
|
6
|
+
require File.dirname(__FILE__) + '/lib/google_text/version'
|
7
|
+
|
8
|
+
system "git tag v#{GoogleText::Version}"
|
9
|
+
sh "gem build google_text.gemspec"
|
10
|
+
sh "gem push google_text-#{GoogleText::Version}.gem"
|
11
|
+
sh "git push origin master --tags"
|
12
|
+
sh "git clean -fd"
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
desc "Install gem locally"
|
17
|
+
task :install do
|
18
|
+
require File.dirname(__FILE__) + '/lib/google_text/version'
|
19
|
+
sh "gem build google_text.gemspec"
|
20
|
+
sh "sudo gem install ./google_text-#{GoogleText::Version}.gem"
|
21
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/lib/google_text.rb
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
module GoogleText
|
2
|
+
class Client
|
3
|
+
attr_accessor :configuration, :session, :account, :xsrf_token, :session_id, :messages,
|
4
|
+
:login_url, :dashboard_url, :inbox_url, :mark_as_read_url, :send_url,
|
5
|
+
:service
|
6
|
+
|
7
|
+
def initialize(options={})
|
8
|
+
@configuration = GoogleText.configuration
|
9
|
+
|
10
|
+
[:login_url, :dashboard_url, :inbox_url, :mark_as_read_url, :send_url, :service].each do |key|
|
11
|
+
self.send("#{key}=", options[key] || @configuration.send(key))
|
12
|
+
end
|
13
|
+
|
14
|
+
@account = Account.new(@configuration.email,@configuration.password)
|
15
|
+
@messages = []
|
16
|
+
establish_session
|
17
|
+
end
|
18
|
+
|
19
|
+
def login
|
20
|
+
get_xsrf_token
|
21
|
+
post_to_login
|
22
|
+
get_session_id
|
23
|
+
end
|
24
|
+
|
25
|
+
def logged_in?
|
26
|
+
!session_id.nil?
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_xsrf_token
|
30
|
+
@xsrf_token = parser.xsrf_token_from login_page
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_session_id
|
34
|
+
begin
|
35
|
+
@session_id = parser.session_id_from dashboard_page
|
36
|
+
rescue
|
37
|
+
raise "Could not retrieve Google Voice Session ID"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def send_message(phone_number,text)
|
42
|
+
fields = fields_for 'phoneNumber' => phone_number, 'text' => text, '_rnr_se' => session_id
|
43
|
+
post send_url, fields
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_messages
|
47
|
+
@messages = parser.messages_from inbox_page
|
48
|
+
end
|
49
|
+
|
50
|
+
def mark_as_read(id)
|
51
|
+
fields = fields_for 'messages' => id, 'read' => 1, '_rnr_se' => session_id
|
52
|
+
post mark_as_read_url, fields
|
53
|
+
end
|
54
|
+
|
55
|
+
def current_page
|
56
|
+
@session.body
|
57
|
+
end
|
58
|
+
|
59
|
+
#TODO: this does not update when being forwarded, prolly need to access last response object directly
|
60
|
+
def current_url
|
61
|
+
@session.url
|
62
|
+
end
|
63
|
+
|
64
|
+
def inbox_page
|
65
|
+
get inbox_url
|
66
|
+
end
|
67
|
+
|
68
|
+
def dashboard_page
|
69
|
+
current_url == @configuration.dashboard_url ? current_page : get(dashboard_url)
|
70
|
+
end
|
71
|
+
|
72
|
+
def post_to_login
|
73
|
+
post login_url, login_fields
|
74
|
+
end
|
75
|
+
|
76
|
+
def login_page
|
77
|
+
get login_url
|
78
|
+
end
|
79
|
+
|
80
|
+
def parser
|
81
|
+
@parser ||= Parser.new
|
82
|
+
end
|
83
|
+
|
84
|
+
protected
|
85
|
+
|
86
|
+
def establish_session
|
87
|
+
@session ||= Session.new
|
88
|
+
end
|
89
|
+
|
90
|
+
def get(*args)
|
91
|
+
@session.get(*args)
|
92
|
+
end
|
93
|
+
|
94
|
+
def post(*args)
|
95
|
+
@session.post(*args)
|
96
|
+
end
|
97
|
+
|
98
|
+
def login_fields
|
99
|
+
fields_for 'continue' => dashboard_url,
|
100
|
+
'service' => service,
|
101
|
+
'GALX' => xsrf_token,
|
102
|
+
'Email' => account.email,
|
103
|
+
'Passwd' => account.password
|
104
|
+
end
|
105
|
+
|
106
|
+
def fields_for(fields={})
|
107
|
+
fields = fields.map do |name,value|
|
108
|
+
value.nil? ? nil : Curl::PostField.content(name, value)
|
109
|
+
end
|
110
|
+
fields.compact
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module GoogleText
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :email, :password, :login_url, :user_agent, :dashboard_url, :inbox_url, :service, :send_url, :mark_as_read_url
|
4
|
+
|
5
|
+
DEFAULTS = {
|
6
|
+
:login_url => 'https://www.google.com/accounts/ServiceLoginAuth',
|
7
|
+
:dashboard_url => 'https://www.google.com/voice',
|
8
|
+
:mark_as_read_url => 'https://www.google.com/voice/inbox/mark',
|
9
|
+
:inbox_url => 'https://www.google.com/voice/inbox/recent',
|
10
|
+
:send_url => 'https://www.google.com/voice/sms/send',
|
11
|
+
:service => 'grandcentral',
|
12
|
+
:user_agent => 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2',
|
13
|
+
}
|
14
|
+
|
15
|
+
def initialize(options={})
|
16
|
+
DEFAULTS.each do |key,value|
|
17
|
+
self.send("#{key}=", options[key] || value)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def reset!
|
22
|
+
DEFAULTS.each do |key,value|
|
23
|
+
self.send("#{key}=", value)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
class << self
|
30
|
+
attr_accessor :configuration
|
31
|
+
end
|
32
|
+
|
33
|
+
# Configure GoogleText someplace sensible,
|
34
|
+
# like config/initializers/google_text.rb when using Rails
|
35
|
+
#
|
36
|
+
#
|
37
|
+
# @example
|
38
|
+
# GoogleText.configure do |config|
|
39
|
+
# config.email = 'google-user'
|
40
|
+
# config.password = 'google-password'
|
41
|
+
# end
|
42
|
+
def self.configure
|
43
|
+
self.configuration ||= Configuration.new
|
44
|
+
yield(configuration)
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module GoogleText
|
2
|
+
class Message
|
3
|
+
attr_accessor :text, :to, :from, :start_time, :display_start_time, :relative_start_time, :display_number, :labels, :display_start_date_time, :id, :read_status, :client
|
4
|
+
|
5
|
+
def initialize(options={})
|
6
|
+
self.text = options[:text]
|
7
|
+
self.to = options[:to].to_s.gsub(/\D/,'')
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.recent
|
11
|
+
client.login
|
12
|
+
client.get_messages
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.unread
|
16
|
+
recent.find_all {|message| !message.read?}
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.client(options={})
|
20
|
+
@client ||= Client.new(options)
|
21
|
+
end
|
22
|
+
|
23
|
+
def send
|
24
|
+
client.login
|
25
|
+
client.send_message(to,text)
|
26
|
+
mark_as_sent
|
27
|
+
return self
|
28
|
+
end
|
29
|
+
|
30
|
+
def mark_as_read
|
31
|
+
client.login
|
32
|
+
client.mark_as_read(id)
|
33
|
+
return self
|
34
|
+
end
|
35
|
+
|
36
|
+
def mark_as_sent
|
37
|
+
@sent_status = true
|
38
|
+
end
|
39
|
+
|
40
|
+
def read?
|
41
|
+
@read_status == true
|
42
|
+
end
|
43
|
+
|
44
|
+
def sent?
|
45
|
+
@sent_status == true
|
46
|
+
end
|
47
|
+
|
48
|
+
def valid?
|
49
|
+
!text.nil? && to.match(/\d{7,}/)
|
50
|
+
end
|
51
|
+
|
52
|
+
def client
|
53
|
+
@client ||= self.class.client
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module GoogleText
|
2
|
+
class Parser
|
3
|
+
attr_accessor :messages
|
4
|
+
|
5
|
+
CSS_SELECTORS = {
|
6
|
+
:session_id => 'form#gc-search-form',
|
7
|
+
:xsrf_token => 'div.loginBox table#gaia_table input',
|
8
|
+
:message_row => 'div.gc-message-sms-row',
|
9
|
+
:message_from => 'span.gc-message-sms-from',
|
10
|
+
:message_time => 'span.gc-message-sms-time',
|
11
|
+
:message_text => 'span.gc-message-sms-text'
|
12
|
+
}
|
13
|
+
|
14
|
+
def session_id_from(string)
|
15
|
+
section = html_for parse_document(string), CSS_SELECTORS[:session_id]
|
16
|
+
section.match(/value="(.+)"/)[1]
|
17
|
+
end
|
18
|
+
|
19
|
+
def xsrf_token_from(string)
|
20
|
+
token = nil
|
21
|
+
html_for parse_fragment(string), CSS_SELECTORS[:xsrf_token] do |input|
|
22
|
+
if input.to_s =~ /GALX/
|
23
|
+
token = input.to_s.scan(/value\="(.+?)"/).flatten.pop
|
24
|
+
end
|
25
|
+
end
|
26
|
+
return token
|
27
|
+
end
|
28
|
+
|
29
|
+
def messages_from(string)
|
30
|
+
@messages = []
|
31
|
+
document = Nokogiri::XML.parse string
|
32
|
+
html_fragment = parse_fragment document.to_html
|
33
|
+
string = document.css('json').first.to_s.scan(/CDATA\[(.+)\]\]/).flatten
|
34
|
+
inbox = JSON.parse(string.first)
|
35
|
+
parse_messages(inbox['messages'], html_fragment)
|
36
|
+
return @messages
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
def html_for(string,selector)
|
42
|
+
selected = string.css(selector)
|
43
|
+
if block_given?
|
44
|
+
selected.each do |item|
|
45
|
+
yield(item)
|
46
|
+
end
|
47
|
+
else
|
48
|
+
selected.inner_html
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def parse_document(string)
|
53
|
+
Nokogiri::HTML::Document.parse(string)
|
54
|
+
end
|
55
|
+
|
56
|
+
def parse_fragment(string)
|
57
|
+
Nokogiri::HTML::DocumentFragment.parse(string)
|
58
|
+
end
|
59
|
+
|
60
|
+
def parse_messages(json_messages, page_fragment)
|
61
|
+
build_messages(json_messages)
|
62
|
+
read_message_details(page_fragment)
|
63
|
+
return @messages
|
64
|
+
end
|
65
|
+
|
66
|
+
def build_messages(json_messages)
|
67
|
+
json_messages.each do |json_message|
|
68
|
+
if json_message[1]['type'].to_i == 2
|
69
|
+
next
|
70
|
+
else
|
71
|
+
@messages << parse_message(json_message)
|
72
|
+
end
|
73
|
+
@messages.sort_by {|message| message.start_time}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def read_message_details(page_fragment)
|
78
|
+
@messages.each do |message|
|
79
|
+
html_for page_fragment, CSS_SELECTORS[:message_row] do |row|
|
80
|
+
if html_for(row,CSS_SELECTORS[:message_from]).strip! =~ /Me:/
|
81
|
+
next
|
82
|
+
elsif html_for(row, CSS_SELECTORS[:message_time]) =~ Regexp.new(message.display_start_time)
|
83
|
+
message.to = 'Me'
|
84
|
+
message.from = html_for(row, CSS_SELECTORS[:message_from]).strip!.gsub!(':', '')
|
85
|
+
message.text = html_for row, CSS_SELECTORS[:message_text]
|
86
|
+
else
|
87
|
+
next
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def parse_message(json_array)
|
94
|
+
message = Message.new
|
95
|
+
message.id = json_array[0]
|
96
|
+
message.start_time = json_array[1]['startTime'].to_i
|
97
|
+
message.read_status = json_array[1]['isRead']
|
98
|
+
message.display_start_time = json_array[1]['displayStartTime']
|
99
|
+
message.relative_start_time = json_array[1]['relativeStartTime']
|
100
|
+
message.display_number = json_array[1]['displayNumber']
|
101
|
+
message.display_start_date_time = json_array[1]['displayStartDateTime']
|
102
|
+
message.labels = json_array[1]['labels']
|
103
|
+
return message
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module GoogleText
|
2
|
+
class Session
|
3
|
+
def initialize
|
4
|
+
@proxy = Curl::Easy.new do |curl|
|
5
|
+
curl.headers["User-Agent"] = GoogleText.configuration.user_agent
|
6
|
+
curl.follow_location = true
|
7
|
+
curl.enable_cookies = true
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def body
|
12
|
+
@proxy.body_str
|
13
|
+
end
|
14
|
+
|
15
|
+
def get(url)
|
16
|
+
self.url = url
|
17
|
+
@proxy.perform
|
18
|
+
handle_response
|
19
|
+
end
|
20
|
+
|
21
|
+
def post(url,fields=[])
|
22
|
+
self.url = url
|
23
|
+
@proxy.http_post fields
|
24
|
+
handle_response
|
25
|
+
end
|
26
|
+
|
27
|
+
def url
|
28
|
+
@proxy.url
|
29
|
+
end
|
30
|
+
|
31
|
+
def url=(url)
|
32
|
+
@proxy.url = url
|
33
|
+
end
|
34
|
+
|
35
|
+
def response_code
|
36
|
+
@proxy.response_code
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
def handle_response
|
42
|
+
if response_code == 200
|
43
|
+
body
|
44
|
+
else
|
45
|
+
raise "Invalid Response: #{response_code}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GoogleText::Client do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
GoogleText.configure do |config|
|
7
|
+
config.email = 'baltimore'
|
8
|
+
config.password = 'crabcakes'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:client) { GoogleText::Client.new }
|
13
|
+
|
14
|
+
it "should have established a GoogleText::Session obect" do
|
15
|
+
client.session.should be_a(GoogleText::Session)
|
16
|
+
end
|
17
|
+
|
18
|
+
context "#get_xsrf_token" do
|
19
|
+
before(:all) do
|
20
|
+
client.stub!(:login_page).and_return(File.read("spec/data/login_url.html"))
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should return a valid xsrf_token" do
|
24
|
+
client.get_xsrf_token
|
25
|
+
client.xsrf_token.should_not be_nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "#login" do
|
30
|
+
before(:each) do
|
31
|
+
client.stub!(:login_page).and_return(File.read("spec/data/login_url.html"))
|
32
|
+
client.stub!(:post_to_login).and_return(true)
|
33
|
+
client.stub!(:dashboard_page).and_return(File.read("spec/data/dashboard_url.html"))
|
34
|
+
client.login
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should return a valid xsrf_token" do
|
38
|
+
client.xsrf_token.should_not be_nil
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should advance the current page to GV dashboard which includes the account's phone number" do
|
42
|
+
client.dashboard_page.should include('(312) 123-4567')
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should retrieve the session id" do
|
46
|
+
client.session_id.should == 'WK7fnEZoPCizMP2Nx7UdqTdFnMA='
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "get_messages" do
|
51
|
+
before(:all) do
|
52
|
+
client.stub!(:login_page).and_return(File.read("spec/data/login_url.html"))
|
53
|
+
client.stub!(:post_to_login).and_return(true)
|
54
|
+
client.stub!(:dashboard_page).and_return(File.read("spec/data/dashboard_url.html"))
|
55
|
+
client.stub!(:inbox_page).and_return(File.read("spec/data/recent_messages.html"))
|
56
|
+
end
|
57
|
+
|
58
|
+
let(:messages) do
|
59
|
+
client.login
|
60
|
+
client.get_messages
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should return an non empty array" do
|
64
|
+
messages.should_not be_empty
|
65
|
+
end
|
66
|
+
|
67
|
+
context "message" do
|
68
|
+
let(:message) {messages.first}
|
69
|
+
|
70
|
+
subject { message }
|
71
|
+
|
72
|
+
it {should be_a GoogleText::Message}
|
73
|
+
|
74
|
+
it "should have the correct from number" do
|
75
|
+
message.from.should == "+13121234567"
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should have the correct message text" do
|
79
|
+
message.text.should == "Another message"
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should be marked as unread" do
|
83
|
+
message.should_not be_read
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GoogleText::Configuration do
|
4
|
+
before(:all) do
|
5
|
+
GoogleText.configure do |config|
|
6
|
+
config.email = 'baltimore'
|
7
|
+
config.password = 'crabcakes'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
after(:all) do
|
12
|
+
GoogleText.configuration.reset!
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:configuration) { GoogleText.configuration }
|
16
|
+
|
17
|
+
subject { configuration }
|
18
|
+
|
19
|
+
it "should be set to supplied email address" do
|
20
|
+
configuration.email.should == 'baltimore'
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should be set to supplied password" do
|
24
|
+
configuration.password.should == 'crabcakes'
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should be set to the default dashboard_url when none is configured" do
|
28
|
+
configuration.dashboard_url.should == "https://www.google.com/voice"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should overwrite default dashboard_url when supplied" do
|
32
|
+
GoogleText.configure do |config|
|
33
|
+
config.dashboard_url = 'https://www.google.com/voice_portal'
|
34
|
+
end
|
35
|
+
configuration.dashboard_url.should == 'https://www.google.com/voice_portal'
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GoogleText::Message do
|
4
|
+
before(:all) do
|
5
|
+
GoogleText.configure do |config|
|
6
|
+
config.email = 'baltimore'
|
7
|
+
config.password = 'crabcakes'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:message) { GoogleText::Message.new :to => '(312) 123-4567', :text => "Hello World" }
|
12
|
+
|
13
|
+
subject { message }
|
14
|
+
|
15
|
+
it "should have stripped non-numeric characters from the phone number" do
|
16
|
+
message.to.should == '3121234567'
|
17
|
+
end
|
18
|
+
|
19
|
+
it { should be_valid }
|
20
|
+
|
21
|
+
context "send" do
|
22
|
+
before(:each) do
|
23
|
+
message.client.stub!(:login_page).and_return(File.read("spec/data/login_url.html"))
|
24
|
+
message.client.stub!(:post_to_login).and_return(true)
|
25
|
+
message.client.stub!(:dashboard_page).and_return(File.read("spec/data/dashboard_url.html"))
|
26
|
+
message.client.stub!(:send_message).and_return(true)
|
27
|
+
end
|
28
|
+
it "should return a Message Object" do
|
29
|
+
message.send.should be_a GoogleText::Message
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should mark message as sent" do
|
33
|
+
message.send
|
34
|
+
message.should be_sent
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: google_text
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Sebastian Friedrich
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-06-16 00:00:00 -05:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: curb
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
- 7
|
30
|
+
- 6
|
31
|
+
version: 0.7.6
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: nokogiri
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 0
|
43
|
+
version: "0"
|
44
|
+
type: :runtime
|
45
|
+
version_requirements: *id002
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: json
|
48
|
+
prerelease: false
|
49
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
segments:
|
54
|
+
- 0
|
55
|
+
version: "0"
|
56
|
+
type: :runtime
|
57
|
+
version_requirements: *id003
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: rspec
|
60
|
+
prerelease: false
|
61
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
segments:
|
66
|
+
- 0
|
67
|
+
version: "0"
|
68
|
+
type: :development
|
69
|
+
version_requirements: *id004
|
70
|
+
description: GoogleText is a SMS client library for sending and receiving free SMS through Google Voice. GoogleText uses Curl and Nokogiri to scrape and post using your regular Google Voice service URLs.
|
71
|
+
email: sebastian@feldpost.com
|
72
|
+
executables: []
|
73
|
+
|
74
|
+
extensions: []
|
75
|
+
|
76
|
+
extra_rdoc_files: []
|
77
|
+
|
78
|
+
files:
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- LICENSE
|
82
|
+
- CONTRIBUTORS
|
83
|
+
- HISTORY.md
|
84
|
+
- VERSION
|
85
|
+
- lib/google_text/account.rb
|
86
|
+
- lib/google_text/client.rb
|
87
|
+
- lib/google_text/configuration.rb
|
88
|
+
- lib/google_text/message.rb
|
89
|
+
- lib/google_text/parser.rb
|
90
|
+
- lib/google_text/session.rb
|
91
|
+
- lib/google_text/version.rb
|
92
|
+
- lib/google_text.rb
|
93
|
+
- spec/google-text/client_spec.rb
|
94
|
+
- spec/google-text/configuration_spec.rb
|
95
|
+
- spec/google-text/message_spec.rb
|
96
|
+
- spec/spec_helper.rb
|
97
|
+
has_rdoc: true
|
98
|
+
homepage: http://github.com/feldpost/google_text
|
99
|
+
licenses: []
|
100
|
+
|
101
|
+
post_install_message:
|
102
|
+
rdoc_options: []
|
103
|
+
|
104
|
+
require_paths:
|
105
|
+
- lib
|
106
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
segments:
|
111
|
+
- 0
|
112
|
+
version: "0"
|
113
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
segments:
|
118
|
+
- 0
|
119
|
+
version: "0"
|
120
|
+
requirements: []
|
121
|
+
|
122
|
+
rubyforge_project: google_text
|
123
|
+
rubygems_version: 1.3.6
|
124
|
+
signing_key:
|
125
|
+
specification_version: 3
|
126
|
+
summary: GoogleText is a SMS client library for sending and receiving free SMS through Google Voice.
|
127
|
+
test_files:
|
128
|
+
- spec/google-text/client_spec.rb
|
129
|
+
- spec/google-text/configuration_spec.rb
|
130
|
+
- spec/google-text/message_spec.rb
|