tit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/ChangeLog.markdown +7 -0
- data/LICENSE +3 -0
- data/README.markdown +43 -0
- data/Rakefile +16 -0
- data/VERSION.yml +5 -0
- data/bin/tit +130 -0
- data/lib/tit.rb +231 -0
- data/tit.gemspec +55 -0
- metadata +84 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
pkg
|
data/ChangeLog.markdown
ADDED
data/LICENSE
ADDED
data/README.markdown
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
tit
|
2
|
+
===
|
3
|
+
|
4
|
+
a rather spiteful stupid fucking twitter client for you and your stupid fucking
|
5
|
+
friends
|
6
|
+
|
7
|
+
install
|
8
|
+
-------
|
9
|
+
|
10
|
+
$ (sudo) gem install tit
|
11
|
+
|
12
|
+
usage
|
13
|
+
-----
|
14
|
+
|
15
|
+
$ tit
|
16
|
+
|
17
|
+
or
|
18
|
+
|
19
|
+
$ tit -u "look at my stupid fucking tweet" -G 88.918:-34.879
|
20
|
+
|
21
|
+
or
|
22
|
+
|
23
|
+
$ tit -P -n
|
24
|
+
|
25
|
+
dependencies
|
26
|
+
------------
|
27
|
+
|
28
|
+
[rest-client][] and [nokogiri][]
|
29
|
+
|
30
|
+
caveats
|
31
|
+
-------
|
32
|
+
|
33
|
+
geotags are of the form `LAT:LONG`, where `LAT` and `LONG` are floating point
|
34
|
+
numbers, indicating, respectively, the number of degrees north or east of the
|
35
|
+
center of the earth; make them negative if you live on one or both of the dark
|
36
|
+
hemispheres
|
37
|
+
|
38
|
+
bugs
|
39
|
+
----
|
40
|
+
|
41
|
+
yeah probably; some of the code is super fucking confusing so you might have
|
42
|
+
trouble fixing them but it doesn't do much so I don't think there are many
|
43
|
+
issues
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
begin
|
2
|
+
require 'jeweler'
|
3
|
+
Jeweler::Tasks.new do |gemspec|
|
4
|
+
gemspec.name = "tit"
|
5
|
+
gemspec.summary = "stupid fucking twitter client"
|
6
|
+
gemspec.description = "a stupid fucking twitter client"
|
7
|
+
gemspec.email = "leif.walsh@gmail.com"
|
8
|
+
gemspec.homepage = "http://github.com/adlaiff6/tit"
|
9
|
+
gemspec.authors = ["Leif Walsh"]
|
10
|
+
gemspec.add_dependency('nokogiri', '>= 1.4.0')
|
11
|
+
gemspec.add_dependency('rest-client', '>= 1.2.0')
|
12
|
+
end
|
13
|
+
Jeweler::GemcutterTasks.new
|
14
|
+
rescue LoadError
|
15
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
16
|
+
end
|
data/VERSION.yml
ADDED
data/bin/tit
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'tit'
|
4
|
+
|
5
|
+
def main
|
6
|
+
options = {
|
7
|
+
:debug => false,
|
8
|
+
:action => :home,
|
9
|
+
:wait => nil,
|
10
|
+
:payload => nil,
|
11
|
+
:notify => nil
|
12
|
+
}
|
13
|
+
|
14
|
+
tit = Tit.new
|
15
|
+
|
16
|
+
tit.opts = OptionParser.new do |opts|
|
17
|
+
opts.banner = "Usage: #{File.basename($0)} " +
|
18
|
+
"[options] [action [action options]]"
|
19
|
+
|
20
|
+
opts.separator ""
|
21
|
+
opts.separator "Actions:"
|
22
|
+
|
23
|
+
opts.on("-p", "--public", "Show public timeline") do
|
24
|
+
options[:action] = :public
|
25
|
+
end
|
26
|
+
opts.on("-H", "--home", "Show home timeline (default)") do
|
27
|
+
options[:action] = :home
|
28
|
+
end
|
29
|
+
opts.on("-m", "--mentions", "Show mentions timeline") do
|
30
|
+
options[:action] = :mentions
|
31
|
+
end
|
32
|
+
opts.on("-u", "--update [STATUS]",
|
33
|
+
"Update status (read from STDIN if none given)") do |status|
|
34
|
+
options[:action] = :update
|
35
|
+
options[:payload] ||= {}
|
36
|
+
options[:payload]["status"] = status || STDIN
|
37
|
+
end
|
38
|
+
|
39
|
+
opts.separator ""
|
40
|
+
opts.separator "Receive options (public/home/mentions):"
|
41
|
+
|
42
|
+
opts.on("-P", "--poll [N]",
|
43
|
+
"Poll for more updates every N secs (default 180)") do |secs|
|
44
|
+
options[:wait] = secs || '180'
|
45
|
+
options[:wait] = options[:wait].to_i
|
46
|
+
options[:wait] = 30 if options[:wait] < 30
|
47
|
+
end
|
48
|
+
|
49
|
+
opts.separator ""
|
50
|
+
opts.separator "Poll options:"
|
51
|
+
|
52
|
+
opts.on("-n", "--notify [PROG]",
|
53
|
+
"Send notifications using PROG (default: notify-send)") do |prog|
|
54
|
+
options[:notify] = prog || "notify-send"
|
55
|
+
end
|
56
|
+
|
57
|
+
opts.separator ""
|
58
|
+
opts.separator "Update options:"
|
59
|
+
|
60
|
+
opts.on("-G", "--geo LAT:LONG",
|
61
|
+
"Set latitude and longitude for update") do |s|
|
62
|
+
sp = s.split(/:/)
|
63
|
+
|
64
|
+
tit.abort("invalid geotag format: #{s}", opts) unless sp.length == 2
|
65
|
+
|
66
|
+
options[:payload] ||= {}
|
67
|
+
options[:payload]["lat"] = sp[0]
|
68
|
+
options[:payload]["long"] = sp[1]
|
69
|
+
end
|
70
|
+
|
71
|
+
opts.separator ""
|
72
|
+
opts.separator "Common options:"
|
73
|
+
|
74
|
+
opts.on("-d", "--debug", "Show debugging information") do
|
75
|
+
options[:debug] = true
|
76
|
+
end
|
77
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
78
|
+
puts opts
|
79
|
+
exit
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
begin
|
84
|
+
tit.opts.parse!
|
85
|
+
rescue OptionParser::InvalidOption => e
|
86
|
+
tit.abort(e.message)
|
87
|
+
end
|
88
|
+
|
89
|
+
# check for option errors
|
90
|
+
if Tit::READERS.include? options[:action]
|
91
|
+
tit.abort("cannot provide geotag when reading") unless options[:payload].nil?
|
92
|
+
tit.abort("cannot notify unless polling") if (options[:wait].nil? and
|
93
|
+
not options[:notify].nil?)
|
94
|
+
end
|
95
|
+
if options[:action] == :update
|
96
|
+
tit.abort("need status message") unless options[:payload].include? "status"
|
97
|
+
tit.abort("can't repeatedly update status") unless options[:wait].nil?
|
98
|
+
tit.abort("can't notify when updating status") unless options[:notify].nil?
|
99
|
+
end
|
100
|
+
|
101
|
+
# do it
|
102
|
+
if options[:debug]
|
103
|
+
begin
|
104
|
+
tit.run(options)
|
105
|
+
rescue SocketError, Errno::ENETUNREACH, Errno::ETIMEDOUT, RestClient::Exception => e
|
106
|
+
tit.error "got a networking error, are you connected to the intarbutts?"
|
107
|
+
puts e
|
108
|
+
exit(-1)
|
109
|
+
end
|
110
|
+
else
|
111
|
+
begin
|
112
|
+
tit.run(options)
|
113
|
+
rescue SocketError, Errno::ENETUNREACH, Errno::ETIMEDOUT, RestClient::Exception => e
|
114
|
+
tit.error "got a networking error, are you connected to the intarbutts?"
|
115
|
+
puts e
|
116
|
+
exit(-1)
|
117
|
+
rescue => e
|
118
|
+
tit.error "unknown error"
|
119
|
+
puts e
|
120
|
+
exit(-1)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
begin
|
126
|
+
main
|
127
|
+
rescue Interrupt
|
128
|
+
puts ""
|
129
|
+
exit(130)
|
130
|
+
end
|
data/lib/tit.rb
ADDED
@@ -0,0 +1,231 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'ftools'
|
5
|
+
require 'nokogiri'
|
6
|
+
require 'optparse'
|
7
|
+
require 'rest_client'
|
8
|
+
require 'time' # heh.
|
9
|
+
require 'yaml'
|
10
|
+
|
11
|
+
class String
|
12
|
+
def wrapped(cols)
|
13
|
+
curlen = 0
|
14
|
+
split.inject([[]]) do |rows, word|
|
15
|
+
if curlen + word.length > cols
|
16
|
+
curlen = word.length + 1
|
17
|
+
rows << [word]
|
18
|
+
else
|
19
|
+
curlen += word.length + 1
|
20
|
+
rows << (rows.pop << word)
|
21
|
+
end
|
22
|
+
end.map { |row| row.join(' ') }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Time
|
27
|
+
def time_ago_in_words
|
28
|
+
t = Time.now
|
29
|
+
secs = t - self
|
30
|
+
minutes = secs / 60
|
31
|
+
hours = minutes / 60
|
32
|
+
days = hours / 24
|
33
|
+
if hours <= 12 # show a fuzzy time
|
34
|
+
if hours > 2
|
35
|
+
"#{hours.to_i} hours ago"
|
36
|
+
elsif hours > 1
|
37
|
+
"about an hour ago"
|
38
|
+
elsif minutes > 2
|
39
|
+
"#{minutes.to_i} minutes ago"
|
40
|
+
elsif minutes > 1
|
41
|
+
"about a minute ago"
|
42
|
+
else
|
43
|
+
"just now"
|
44
|
+
end
|
45
|
+
elsif days <= 15 # show time ago in days, with time if it was yesterday or today
|
46
|
+
if t.day == day
|
47
|
+
"today at #{strftime("%X")}"
|
48
|
+
elsif t.day - day == 1
|
49
|
+
"yesterday at #{strftime("%X")}"
|
50
|
+
else
|
51
|
+
"#{days.to_i} days ago"
|
52
|
+
end
|
53
|
+
else # time in months or years
|
54
|
+
months = t.month - month + (t.year - year) * 12
|
55
|
+
if months <= 6
|
56
|
+
if months == 1
|
57
|
+
"last month"
|
58
|
+
elsif t.year == year
|
59
|
+
"this #{strftime("%B")}"
|
60
|
+
else
|
61
|
+
"last #{strftime("%B")}"
|
62
|
+
end
|
63
|
+
else
|
64
|
+
if t.year - year == 1
|
65
|
+
"last year"
|
66
|
+
else
|
67
|
+
"#{t.year - year} years ago"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
=begin rdoc
|
75
|
+
Why are you reading the documentation, you cunt?
|
76
|
+
=end
|
77
|
+
class Tit
|
78
|
+
RCFILE = File.join(ENV["HOME"], ".titrc")
|
79
|
+
|
80
|
+
READERS = [:public, :home, :mentions]
|
81
|
+
WRITERS = [:update]
|
82
|
+
|
83
|
+
URLS = {
|
84
|
+
:public => "statuses/public_timeline.xml",
|
85
|
+
:home => "statuses/home_timeline.xml",
|
86
|
+
:mentions => "statuses/mentions.xml",
|
87
|
+
:update => "statuses/update.xml"
|
88
|
+
}
|
89
|
+
|
90
|
+
def initialize
|
91
|
+
@username = nil
|
92
|
+
@password = nil
|
93
|
+
begin
|
94
|
+
File.open(RCFILE, "r") do |rc|
|
95
|
+
data = YAML.load(rc)
|
96
|
+
@username = data["username"]
|
97
|
+
@password = data["password"]
|
98
|
+
end
|
99
|
+
rescue Errno::ENOENT => e
|
100
|
+
File.open(RCFILE, "w") do |rc|
|
101
|
+
YAML.dump({
|
102
|
+
"username" => "<username>",
|
103
|
+
"password" => "<password>"
|
104
|
+
}, rc)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
if @username.nil? or @username.eql? "<username>" or
|
109
|
+
@password.nil? or @password.eql? "<password>"
|
110
|
+
puts "Please fill in your username and password in #{RCFILE}"
|
111
|
+
exit(-1)
|
112
|
+
end
|
113
|
+
|
114
|
+
# set up proxy
|
115
|
+
RestClient.proxy = ENV['https_proxy']
|
116
|
+
|
117
|
+
# get terminal width
|
118
|
+
@cols = %x[tput cols].to_i
|
119
|
+
end
|
120
|
+
attr_accessor :opts
|
121
|
+
|
122
|
+
def resource
|
123
|
+
RestClient::Resource.new("https://#{@username}:#{@password}@twitter.com/")
|
124
|
+
end
|
125
|
+
|
126
|
+
def get_tits(action)
|
127
|
+
Nokogiri.XML(resource[URLS[action]].get).xpath("//status").map do |xml|
|
128
|
+
{
|
129
|
+
:username => xml.at_xpath("./user/name").content,
|
130
|
+
:userid => xml.at_xpath("./user/screen_name").content,
|
131
|
+
:text => xml.xpath("./text").map { |n| n.content },
|
132
|
+
:timestamp => Time.parse(xml.at_xpath("./created_at").content),
|
133
|
+
:id => xml.at_xpath("./id").content.to_i,
|
134
|
+
:geo => xml.at_xpath("./geo").instance_eval do
|
135
|
+
unless children.empty?
|
136
|
+
n, e = children[1].content.split.map { |s| s.to_f }
|
137
|
+
"#{n.abs}#{n >= 0 ? 'N' : 'S'} #{e.abs}#{e >= 0 ? 'E' : 'W'}"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
}
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def update(payload)
|
145
|
+
if payload["status"] == STDIN
|
146
|
+
payload["status"] = STDIN.read
|
147
|
+
end
|
148
|
+
|
149
|
+
if payload["status"].length > 140
|
150
|
+
puts "your status is too long (by #{payload["status"].length - 140} characters)"
|
151
|
+
puts "here is what would get posted:"
|
152
|
+
payload["status"][0...140].wrapped(@cols - 2).each { |l| puts " #{l}" }
|
153
|
+
exit(-1)
|
154
|
+
end
|
155
|
+
|
156
|
+
resource[URLS[:update]].post(payload)
|
157
|
+
end
|
158
|
+
|
159
|
+
def show_tit(status)
|
160
|
+
person = if status[:userid].eql? @username
|
161
|
+
"you"
|
162
|
+
else
|
163
|
+
"#{status[:username]} (#{status[:userid]})"
|
164
|
+
end
|
165
|
+
at = status[:timestamp].time_ago_in_words
|
166
|
+
if status[:geo].nil?
|
167
|
+
puts "#{person} said, #{at}:"
|
168
|
+
else
|
169
|
+
puts "#{person} said, #{at}, from #{status[:geo]}:"
|
170
|
+
end
|
171
|
+
|
172
|
+
status[:text].each do |line|
|
173
|
+
line.wrapped(@cols - 2).each { |l| puts " #{l}" }
|
174
|
+
end
|
175
|
+
puts ""
|
176
|
+
end
|
177
|
+
|
178
|
+
def poll(wait, action, notify)
|
179
|
+
tits = {}
|
180
|
+
get_tits(action).reverse.each do |status|
|
181
|
+
show_tit(status)
|
182
|
+
tits[status[:id]] = status
|
183
|
+
end
|
184
|
+
last_update = Time.now()
|
185
|
+
loop do
|
186
|
+
print "\r", " " * (s = "Last update was at #{last_update.strftime "%X"}, " +
|
187
|
+
"next update at #{(last_update + wait).strftime "%X"}"
|
188
|
+
print s
|
189
|
+
STDOUT.flush
|
190
|
+
sleep(wait)
|
191
|
+
s.length), "\r"
|
192
|
+
begin
|
193
|
+
num_tits = get_tits(action).reverse.reject do |status|
|
194
|
+
tits.include? status[:id]
|
195
|
+
end.each_with_index do |status, i|
|
196
|
+
if i == 0
|
197
|
+
puts "more updates (at #{Time.now.strftime "%X"}):\n"
|
198
|
+
end
|
199
|
+
show_tit(status)
|
200
|
+
tits[status[:id]] = status
|
201
|
+
end.length
|
202
|
+
%x[#{notify} '#{num_tits} new tit#{num_tits == 1 ? '' : 's'}!'] unless notify.nil? or num_tits == 0
|
203
|
+
last_update = Time.now()
|
204
|
+
rescue SocketError, Errno::ENETUNREACH, Errno::ETIMEDOUT, RestClient::Exception => e
|
205
|
+
puts "networking error, will try again later"
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def run(options)
|
211
|
+
if READERS.include? options[:action]
|
212
|
+
if options[:wait].nil?
|
213
|
+
get_tits(options[:action]).reverse.each &method(:show_tit)
|
214
|
+
else
|
215
|
+
poll(options[:wait], options[:action], options[:notify])
|
216
|
+
end
|
217
|
+
elsif options[:action] == :update
|
218
|
+
update options[:payload]
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def error msg
|
223
|
+
puts "#{File.basename $0}: #{msg}"
|
224
|
+
end
|
225
|
+
|
226
|
+
def abort msg
|
227
|
+
error(msg)
|
228
|
+
puts @opts
|
229
|
+
exit(-1)
|
230
|
+
end
|
231
|
+
end
|
data/tit.gemspec
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{tit}
|
8
|
+
s.version = "1.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Leif Walsh"]
|
12
|
+
s.date = %q{2010-01-22}
|
13
|
+
s.default_executable = %q{tit}
|
14
|
+
s.description = %q{a stupid fucking twitter client}
|
15
|
+
s.email = %q{leif.walsh@gmail.com}
|
16
|
+
s.executables = ["tit"]
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"ChangeLog.markdown",
|
19
|
+
"LICENSE",
|
20
|
+
"README.markdown"
|
21
|
+
]
|
22
|
+
s.files = [
|
23
|
+
".gitignore",
|
24
|
+
"ChangeLog.markdown",
|
25
|
+
"LICENSE",
|
26
|
+
"README.markdown",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION.yml",
|
29
|
+
"bin/tit",
|
30
|
+
"lib/tit.rb",
|
31
|
+
"tit.gemspec"
|
32
|
+
]
|
33
|
+
s.homepage = %q{http://github.com/adlaiff6/tit}
|
34
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
35
|
+
s.require_paths = ["lib"]
|
36
|
+
s.rubygems_version = %q{1.3.5}
|
37
|
+
s.summary = %q{stupid fucking twitter client}
|
38
|
+
|
39
|
+
if s.respond_to? :specification_version then
|
40
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
41
|
+
s.specification_version = 3
|
42
|
+
|
43
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
44
|
+
s.add_runtime_dependency(%q<nokogiri>, [">= 1.4.0"])
|
45
|
+
s.add_runtime_dependency(%q<rest-client>, [">= 1.2.0"])
|
46
|
+
else
|
47
|
+
s.add_dependency(%q<nokogiri>, [">= 1.4.0"])
|
48
|
+
s.add_dependency(%q<rest-client>, [">= 1.2.0"])
|
49
|
+
end
|
50
|
+
else
|
51
|
+
s.add_dependency(%q<nokogiri>, [">= 1.4.0"])
|
52
|
+
s.add_dependency(%q<rest-client>, [">= 1.2.0"])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tit
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Leif Walsh
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-22 00:00:00 +01:00
|
13
|
+
default_executable: tit
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: nokogiri
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.4.0
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rest-client
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.2.0
|
34
|
+
version:
|
35
|
+
description: a stupid fucking twitter client
|
36
|
+
email: leif.walsh@gmail.com
|
37
|
+
executables:
|
38
|
+
- tit
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- ChangeLog.markdown
|
43
|
+
- LICENSE
|
44
|
+
- README.markdown
|
45
|
+
files:
|
46
|
+
- .gitignore
|
47
|
+
- ChangeLog.markdown
|
48
|
+
- LICENSE
|
49
|
+
- README.markdown
|
50
|
+
- Rakefile
|
51
|
+
- VERSION.yml
|
52
|
+
- bin/tit
|
53
|
+
- lib/tit.rb
|
54
|
+
- tit.gemspec
|
55
|
+
has_rdoc: true
|
56
|
+
homepage: http://github.com/adlaiff6/tit
|
57
|
+
licenses: []
|
58
|
+
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options:
|
61
|
+
- --charset=UTF-8
|
62
|
+
require_paths:
|
63
|
+
- lib
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: "0"
|
69
|
+
version:
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: "0"
|
75
|
+
version:
|
76
|
+
requirements: []
|
77
|
+
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 1.3.5
|
80
|
+
signing_key:
|
81
|
+
specification_version: 3
|
82
|
+
summary: stupid fucking twitter client
|
83
|
+
test_files: []
|
84
|
+
|