google_text 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/CONTRIBUTORS ADDED
@@ -0,0 +1 @@
1
+ Sebastian Friedrich
data/HISTORY.md ADDED
@@ -0,0 +1,3 @@
1
+ ## 0.0.1 (2010-6-15)
2
+
3
+ * A gem is born.
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
@@ -0,0 +1,9 @@
1
+ require 'curb'
2
+ require 'nokogiri'
3
+ require 'json'
4
+ require 'google_text/configuration'
5
+ require 'google_text/parser'
6
+ require 'google_text/session'
7
+ require 'google_text/message'
8
+ require 'google_text/account'
9
+ require 'google_text/client'
@@ -0,0 +1,9 @@
1
+ module GoogleText
2
+ class Account
3
+ attr_accessor :email, :password
4
+
5
+ def initialize(email,password)
6
+ @email, @password = email, password
7
+ end
8
+ end
9
+ end
@@ -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,3 @@
1
+ module GoogleText # :nodoc:
2
+ VERSION = Version = File.readlines(File.expand_path('../../../VERSION', __FILE__)).first
3
+ 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
@@ -0,0 +1,5 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../lib/google_text")
2
+
3
+ Rspec.configure do |c|
4
+ c.mock_with :rspec
5
+ end
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