twexicon 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/bin/twexicon +5 -0
- data/config/environment.rb +8 -0
- data/lib/twexicon.rb +1 -0
- data/lib/twexicon/analyzer.rb +184 -0
- data/lib/twexicon/cli.rb +25 -0
- data/lib/twexicon/scraper.rb +27 -0
- data/lib/twexicon/validator.rb +40 -0
- data/lib/twexicon/version.rb +3 -0
- metadata +117 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a1cd602f292631f449f3fe0f20536abbdf98ad4a
|
4
|
+
data.tar.gz: b0a6f7d8c6635cd17ec42754875761ee977b1388
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 392e64484aace879ae529f9f54c44e8e8de403ed5126bc2b182f224d556667dd2b2b4760d0c0a10be21c92fd3cd82c383f072e10613646aeea4c2add05226e26
|
7
|
+
data.tar.gz: fe9d1014c544a9712f97b0bcbf0b18a6758d9763ff628e45a02edef0371590424130d76d344728aeda0779361d8b07367bc63e1f2c0c26aef626448a4b6b4e65
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "twexicon"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/bin/twexicon
ADDED
data/lib/twexicon.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_relative '../config/environment'
|
@@ -0,0 +1,184 @@
|
|
1
|
+
class Twexicon::Analyzer
|
2
|
+
attr_reader :tweets, :username, :input, :int
|
3
|
+
|
4
|
+
def initialize(username, tweets)
|
5
|
+
@username = username
|
6
|
+
@tweets = tweets
|
7
|
+
puts "\nIndexed the #{tweets.size} most recent tweet(s) for @#{username}."
|
8
|
+
run
|
9
|
+
end
|
10
|
+
|
11
|
+
def run
|
12
|
+
quit = false
|
13
|
+
until quit
|
14
|
+
@input = nil
|
15
|
+
@int = ""
|
16
|
+
puts "What would you like to do next? For options, type 'help'."
|
17
|
+
until is_valid?
|
18
|
+
@input = gets.strip.gsub(/\W/, "").downcase
|
19
|
+
end
|
20
|
+
case input
|
21
|
+
when "help", "h"
|
22
|
+
puts "\nTo retrieve one of @#{username}'s #{tweets.size} tweet(s), type 'GET'."
|
23
|
+
puts "To view @#{username}'s ten favorite words, type 'WORDS'."
|
24
|
+
puts "For @#{username}'s favorite things to scream about, type 'SHOUTS'."
|
25
|
+
puts "To see the #hashtags that consume @#{username}'s thoughts, type 'HASHTAGS'."
|
26
|
+
puts "For some Twitter handles that @#{username} has tweeted at, type 'USERNAMES'."
|
27
|
+
puts "To see links for embedded pictures and/or videos, type 'PIX'."
|
28
|
+
puts "To view any other links @#{username} deemed worthy of sharing, type 'LINKS'."
|
29
|
+
puts "For some numbers that @#{username} mentioned, type 'NUMBERS'."
|
30
|
+
puts "To see which short acronyms @#{username} is fond of, type 'ACRONYMS'."
|
31
|
+
puts "To look up a different Twitter handle or to exit the program, type 'EXIT'."
|
32
|
+
puts "Short commands, in order: 'g', 'w', 's', 'ht', 'u', 'p', 'l', 'n', 'a', 'e', and 'h' for 'help'."
|
33
|
+
when "get", "g" then get_tweet
|
34
|
+
when "words", "w" then get_words
|
35
|
+
when "shouts", "s" then get_shouts
|
36
|
+
when "pix", "p" then get_pix
|
37
|
+
when "links", "l" then get_links
|
38
|
+
when "numbers", "n" then get_numbers
|
39
|
+
when "acronyms", "a" then get_acronyms
|
40
|
+
when "hashtags", "ht" then get_hashtags
|
41
|
+
when "usernames", "handles", "u" then get_usernames
|
42
|
+
when "exit", "e" then quit = true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def is_valid?
|
48
|
+
if input =~ /(^help$|^h$|^get$|^g$|^exit$|^e$|^words$|^w$|^shouts$|^s$|^pix$|^p$|^links$|^l$|^numbers$|^n$|^acronyms$|^a$|^hashtags$|^ht$|^usernames$|^handles$|^u$)/
|
49
|
+
true
|
50
|
+
elsif input == nil
|
51
|
+
false
|
52
|
+
else
|
53
|
+
puts "Hm, I didn't recognize that. Please make a valid selection."
|
54
|
+
puts "To display all options, type 'help'."
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_tweet
|
59
|
+
if tweets.size == 1
|
60
|
+
puts "\n@#{username}'s only tweet is: #{tweets[int].keys[1]}"
|
61
|
+
else
|
62
|
+
puts "\nWhich tweet would you like to view?"
|
63
|
+
int = ""
|
64
|
+
until int =~ /^\d+$/ && int.to_i >= 1 && int.to_i <= tweets.size
|
65
|
+
puts "Please specify a number between 1 and #{tweets.size}."
|
66
|
+
int = gets.strip.gsub(/\D/, "")
|
67
|
+
end
|
68
|
+
puts "\n@#{username} said: #{tweets[int.to_i].keys[0]}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# 38 words from https://en.wikipedia.org/wiki/Most_common_words_in_English –– Left out some common yet still interesting ones (People, Good, Think, Work, First, One, Two, Want, New, Give, Know)
|
73
|
+
COMMON_WORDS = ["A", "About", "An", "And", "Are", "As", "At", "Be", "Been", "But", "By", "For", "From", "Get", "Had", "Has", "Have", "In", "Into", "Is", "It", "It's", "Its", "Just", "Not", "Of", "On", "Or", "Say", "So", "Some", "That", "The", "There", "These", "This", "Those", "To", "Up", "With", "I", "My", "Your", "They", "He", "You", "Do", "His", "We", "Her", "She", "Will", "All", "Would", "Their", "What", "Out", "If", "Who", "Which", "Go", "Me", "When", "Make", "Can", "Like", "Time", "No", "Him", "Take", "Year", "Could", "Them", "See", "Other", "Than", "Then", "Now", "Look", "Only", "Come", "Over", "Also", "Back", "After", "Use", "How", "Our", "Well", "Way", "Even", "Because", "Any", "Day", "Most", "Us",
|
74
|
+
# other additions
|
75
|
+
"Wouldn't", "Couldn't", "Shouldn't", "Mustn't", "Would've", "Could've", "Should've", "Must've", "Hadn't", "Wasn't", "Weren't", "Ain't", "Aint", "Here", "Seem", "Seems", "That's", "Took", "Much", "More", "You're", "We're", "We've", "I've", "I'm",
|
76
|
+
# contraction endings until I fix the parsing error
|
77
|
+
"Re", "Ll", "Ve",
|
78
|
+
# Letters until I fix the contraction parsing error
|
79
|
+
"B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
|
80
|
+
|
81
|
+
def get_words
|
82
|
+
words = {}
|
83
|
+
word_array = []
|
84
|
+
tweets.each_value do |v| # Count up instances of each word
|
85
|
+
v.values[0][:words].each do |w|
|
86
|
+
word = w.gsub(/[^\'\w]/, "").capitalize
|
87
|
+
if words.has_key?(word) && !COMMON_WORDS.include?(word)
|
88
|
+
words[word] += 1
|
89
|
+
else
|
90
|
+
words[word] = 1
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
words.each do |w, n| # Create strings for the words that occur >1 times
|
95
|
+
case n
|
96
|
+
when 1..9 then word_array << "0#{n}x #{w}"
|
97
|
+
when 10..99 then word_array << "#{n}x #{w}"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
if word_array.empty?
|
101
|
+
puts "\nIt appears that @#{username} is not much of a talker."
|
102
|
+
else
|
103
|
+
puts "\n@#{username}'s current favorite word(s):"
|
104
|
+
puts word_array.sort.reverse.take(10)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def get_shouts
|
109
|
+
collection = []
|
110
|
+
tweets.each{|num, tweet| collection << tweet.values[0][:shouts]}
|
111
|
+
if collection.flatten.compact.empty?
|
112
|
+
puts "\nIt appears that @#{username} isn't excited by anything."
|
113
|
+
else
|
114
|
+
puts "\n@#{username} shouted about the following things:"
|
115
|
+
collection.flatten.compact.uniq.each{|s| puts s}
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def get_pix
|
120
|
+
collection = []
|
121
|
+
tweets.each{|num, tweet| collection << tweet.values[0][:pix]}
|
122
|
+
if collection.flatten.compact.empty?
|
123
|
+
puts "\nIt appears that @#{username} doesn't think a picture is worth 140 characters."
|
124
|
+
else
|
125
|
+
puts "\n@#{username} shared the following risky clicks:"
|
126
|
+
collection.flatten.compact.uniq.each{|p| puts p}
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def get_links
|
131
|
+
collection = []
|
132
|
+
tweets.each{|num, tweet| collection << tweet.values[0][:links]}
|
133
|
+
if collection.flatten.compact.empty?
|
134
|
+
puts "\nIt appears that @#{username} hasn't found anything worth sharing on the interwebs."
|
135
|
+
else
|
136
|
+
puts "\n@#{username} directed traffic to the following sites:"
|
137
|
+
collection.flatten.compact.uniq.each{|l| puts l}
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def get_numbers
|
142
|
+
collection = []
|
143
|
+
tweets.each{|num, tweet| collection << tweet.values[0][:numbers]}
|
144
|
+
if collection.flatten.compact.empty?
|
145
|
+
puts "\nIt appears that @#{username} isn't a numbers person."
|
146
|
+
else
|
147
|
+
puts "\n@#{username} loves them some digits:"
|
148
|
+
collection.flatten.compact.uniq.each{|n| puts n}
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def get_acronyms
|
153
|
+
collection = []
|
154
|
+
tweets.each{|num, tweet| collection << tweet.values[0][:acronyms]}
|
155
|
+
if collection.flatten.compact.empty?
|
156
|
+
puts "\nIt appears that @#{username} really likes to spell everything out."
|
157
|
+
else
|
158
|
+
puts "\n@#{username} was too lazy to type out the following acronyms:"
|
159
|
+
collection.flatten.compact.uniq.each{|a| puts a}
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def get_hashtags
|
164
|
+
collection = []
|
165
|
+
tweets.each{|num, tweet| collection << tweet.values[0][:hashtags]}
|
166
|
+
if collection.flatten.compact.empty?
|
167
|
+
puts "\nIt appears that @#{username} isn't maximizing their #impressions."
|
168
|
+
else
|
169
|
+
puts "\n@#{username} ameliorated the lack of Thought Leadership on these topics:"
|
170
|
+
collection.flatten.compact.uniq.each{|h| puts h}
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def get_usernames
|
175
|
+
collection = []
|
176
|
+
tweets.each{|num, tweet| collection << tweet.values[0][:usernames]}
|
177
|
+
if collection.flatten.compact.empty?
|
178
|
+
puts "\nIt appears that @#{username} is a bit of a solipsist."
|
179
|
+
else
|
180
|
+
puts "\n@#{username} thinkfluenced the following users:"
|
181
|
+
collection.flatten.compact.uniq{|u| u.downcase}.each{|u| puts u}
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
data/lib/twexicon/cli.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
class Twexicon::CLI
|
2
|
+
def call
|
3
|
+
puts "Welcome to Twexicon."
|
4
|
+
run = true
|
5
|
+
|
6
|
+
while run
|
7
|
+
username = Twexicon::Validator.new.run
|
8
|
+
tweets = Twexicon::Scraper.new(username).refine_tweets
|
9
|
+
if tweets.empty?
|
10
|
+
puts "Unfortunately, @#{username} has never tweeted or has their tweets protected. Sorry about that."
|
11
|
+
else
|
12
|
+
Twexicon::Analyzer.new(username, tweets)
|
13
|
+
end
|
14
|
+
|
15
|
+
input = ""
|
16
|
+
until input =~ /^[yn]$/
|
17
|
+
puts "Would you like to look up tweets from another Twitter handle? [Y/N]"
|
18
|
+
input = gets.strip.gsub(/\W/, "").downcase
|
19
|
+
end
|
20
|
+
input =~ /[n]/ ? run = false : run = true
|
21
|
+
end
|
22
|
+
|
23
|
+
puts "Thank you –– come again!"
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Twexicon::Scraper
|
2
|
+
attr_reader :tweets
|
3
|
+
|
4
|
+
def initialize(username)
|
5
|
+
@tweets = {}
|
6
|
+
scrape_tweets(username)
|
7
|
+
end
|
8
|
+
|
9
|
+
def scrape_tweets(username)
|
10
|
+
Nokogiri::HTML(open("https://twitter.com/#{username}")).css(".tweet-text").each{|t| tweets[tweets.length+1] = {t.text => {:pix => [], :links => [], :hashtags => [], :usernames => [], :numbers => [], :acronyms => [], :shouts => [], :words => []}}}
|
11
|
+
end
|
12
|
+
|
13
|
+
def refine_tweets
|
14
|
+
tweets.each do |num, tweet|
|
15
|
+
t = tweet.keys[0].dup
|
16
|
+
t.scan(/pic.twitter.com\/\w{10}/){|p| tweet.values[0][:pix] << p.strip}.gsub!(/pic.twitter.com\/\w{10}/, " ")
|
17
|
+
t.scan(/https?:\/\/[\w\.\?\=\&\-\/\#]+/){|w| tweet.values[0][:links] << w.strip}.gsub!(/https?:\/\/[\w\.\?\=\&\-\/\#]+/, " ")
|
18
|
+
t.scan(/#\w+/){|h| tweet.values[0][:hashtags] << h.gsub(/\W/, "").prepend("#")}.gsub!(/#\w+/, " ")
|
19
|
+
t.scan(/@\w+/){|u| tweet.values[0][:usernames] << u.gsub(/\W/, "").prepend("@")}.gsub!(/@\w+/, " ")
|
20
|
+
t.scan(/(\d+[:\.\b]?\d*)+/){|n| tweet.values[0][:numbers] << n.first.gsub(/(^\W+|\W+$)/, "")}.gsub!(/(\d+[:\.\b]?\d*)+/, " ")
|
21
|
+
t.scan(/(\b[A-Z][\.\b][A-Z][\.\b][A-Z][\.\b]|\b[A-Z][\.\b][A-Z][\.\b])/){|a| tweet.values[0][:acronyms] << a.first.strip}.gsub!(/(\b[A-Z][\.\b][A-Z][\.\b][A-Z][\.\b]|\b[A-Z][\.\b][A-Z][\.\b])/, " ")
|
22
|
+
t.scan(/(([A-Z]+\W){2,}|[A-Z]{4,}\W)/){|s| tweet.values[0][:shouts] << s.first.gsub(/\W/, " ").strip}.gsub!(/(([A-Z]+\W){2,}|[A-Z]{4,}\W)/, " ")
|
23
|
+
t.scan(/\b[A-Z]{2,3}\b/){|a| tweet.values[0][:acronyms] << a.strip}.gsub!(/\b[A-Z]{2,3}\b/, " ")
|
24
|
+
t.scan(/\w+['\/]?\w*/){|w| tweet.values[0][:words] << w.strip}.gsub!(/\w+['\/]?\w*/, " ")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class Twexicon::Validator
|
2
|
+
attr_reader :username
|
3
|
+
|
4
|
+
TWITTER_RESERVED_WORDS = ["settings", "i", "search", "logout", "login", "download", "signup", "tos", "privacy", "account"]
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@username = ""
|
8
|
+
end
|
9
|
+
|
10
|
+
def run
|
11
|
+
until username.length > 0
|
12
|
+
puts "\nPlease enter a valid Twitter handle:"
|
13
|
+
@username = gets.gsub(/\W/, "")
|
14
|
+
until is_valid?
|
15
|
+
puts "Sorry, that doesn't seem to be a valid Twitter account. Please try again."
|
16
|
+
@username = gets.gsub(/\W/, "")
|
17
|
+
end
|
18
|
+
begin
|
19
|
+
@username = Nokogiri::HTML(open("https://twitter.com/#{username}")).css("span.u-linkComplex-target").first.text
|
20
|
+
rescue OpenURI::HTTPError, NoMethodError
|
21
|
+
puts "Hm, that doesn't seem to be an active Twitter account."
|
22
|
+
@username = ""
|
23
|
+
run
|
24
|
+
rescue SocketError
|
25
|
+
puts "Sorry, the network isn't responding. Please try again."
|
26
|
+
@username = ""
|
27
|
+
run
|
28
|
+
rescue
|
29
|
+
puts "Something went wrong. Please try again."
|
30
|
+
@username = ""
|
31
|
+
run
|
32
|
+
end
|
33
|
+
end
|
34
|
+
"#{username}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def is_valid?
|
38
|
+
username.match(/^\w{1,15}$/) && !TWITTER_RESERVED_WORDS.include?(username.downcase)
|
39
|
+
end
|
40
|
+
end
|
metadata
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: twexicon
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.6
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gabe Jackson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-07-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pry
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.10'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.10'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: nokogiri
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.5'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.5'
|
69
|
+
description: 'When provided a valid Twitter handle, allows for command-line access
|
70
|
+
to the given user''s most recent tweets. Permits the retrieval of individual tweets
|
71
|
+
and can provide ordered lists outlining the following details from the user''s recent
|
72
|
+
tweets: their most frequently used words; any embedded pictures or videos; any embedded
|
73
|
+
hyperlinks; any #hashtags or @usernames mentioned; any numbers, such as years or
|
74
|
+
times of day; any acronyms mentioned; and, last but definitely not least, anything
|
75
|
+
the tweeter felt passionately enough about to SCREAM IN ALL CAPS.'
|
76
|
+
email: gj+code@mail.co.de
|
77
|
+
executables:
|
78
|
+
- twexicon
|
79
|
+
extensions: []
|
80
|
+
extra_rdoc_files: []
|
81
|
+
files:
|
82
|
+
- bin/console
|
83
|
+
- bin/setup
|
84
|
+
- bin/twexicon
|
85
|
+
- config/environment.rb
|
86
|
+
- lib/twexicon.rb
|
87
|
+
- lib/twexicon/analyzer.rb
|
88
|
+
- lib/twexicon/cli.rb
|
89
|
+
- lib/twexicon/scraper.rb
|
90
|
+
- lib/twexicon/validator.rb
|
91
|
+
- lib/twexicon/version.rb
|
92
|
+
homepage: https://github.com/gj/twexicon-cli-gem
|
93
|
+
licenses:
|
94
|
+
- MIT
|
95
|
+
metadata: {}
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
requirements: []
|
111
|
+
rubyforge_project:
|
112
|
+
rubygems_version: 2.6.6
|
113
|
+
signing_key:
|
114
|
+
specification_version: 4
|
115
|
+
summary: CLI gem that returns a given Twitter user's most recent tweets and does some
|
116
|
+
basic textual analysis.
|
117
|
+
test_files: []
|