twexicon 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/bin/twexicon ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/twexicon'
4
+
5
+ Twexicon::CLI.new.call
@@ -0,0 +1,8 @@
1
+ require 'nokogiri'
2
+ require 'open-uri'
3
+
4
+ require_relative '../lib/twexicon/version'
5
+ require_relative '../lib/twexicon/cli'
6
+ require_relative '../lib/twexicon/analyzer'
7
+ require_relative '../lib/twexicon/scraper'
8
+ require_relative '../lib/twexicon/validator'
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
@@ -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
@@ -0,0 +1,3 @@
1
+ module Twexicon
2
+ VERSION = "0.1.6"
3
+ 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: []