awl_tags_twitter 0.0.1 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +9 -24
- data/awl_tags_twitter.gemspec +1 -0
- data/bin/awl_tags_twitter +73 -29
- data/lib/article.rb +2 -2
- data/lib/awl_tags_twitter/version.rb +1 -1
- data/lib/scraper.rb +12 -2
- data/lib/tracker.rb +31 -0
- data/lib/tweet.rb +3 -3
- data/lib/twitter_client.rb +33 -0
- data/spec/article_spec.rb +3 -3
- data/spec/scraper_spec.rb +35 -4
- data/spec/tracker_spec.rb +62 -0
- data/spec/tweet_spec.rb +1 -1
- data/spec/twitter_client.rb +4 -0
- metadata +22 -3
- data/lib/tweet_builder.rb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 681d4e15c326c34421fe0e13a2f6b31635085ca1
|
4
|
+
data.tar.gz: ba7dfc6c47c84f0c39a716eb5db78a79b8761497
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 143093d912537e3005e56b9d25de2b2cc64a31166d9594a6ca773e1d822e3b540767bb506f2c880b7b50a52bacbd77a8a15c6a58c15f1a23ecd304f9fc0ca6ab
|
7
|
+
data.tar.gz: b0399953d0af27dae21a2a7beb95ec409bc746b9e7f62cdba518124b18ed6a4d368e94c631888599edf39e9f18a2521d23b0def3154234ef4a5a2556bd5cc2e3
|
data/README.md
CHANGED
@@ -9,11 +9,17 @@ Grab tags from The Awl posts and tweet them out
|
|
9
9
|
## Usage
|
10
10
|
|
11
11
|
```
|
12
|
-
$ awl_tags_twitter --
|
13
|
-
$ awl_tags_twitter --
|
14
|
-
$ awl_tags_twitter --config /path/to/config/file
|
12
|
+
$ awl_tags_twitter list [--basic | --complex]
|
13
|
+
$ awl_tags_twitter cache-all [--dry]
|
14
|
+
$ awl_tags_twitter tweet --config /path/to/config/file [--dry]
|
15
15
|
```
|
16
16
|
|
17
|
+
### How to retweet a previous Article
|
18
|
+
|
19
|
+
1. You should locate the gem installation location
|
20
|
+
2. Navigate to the tmp directory, and open articles.json
|
21
|
+
3. Remove the article link which you would like to retweet
|
22
|
+
|
17
23
|
## Contributing
|
18
24
|
|
19
25
|
1. Fork it ( https://github.com/ellisandy/awl_tags_twitter/fork )
|
@@ -22,24 +28,3 @@ $ awl_tags_twitter --config /path/to/config/file help
|
|
22
28
|
4. Push to the branch (`git push origin my-new-feature`)
|
23
29
|
5. Create a new Pull Request
|
24
30
|
|
25
|
-
## Archecture
|
26
|
-
1. Scraper returns a list of URLs
|
27
|
-
* These URLs tie to a specific Article
|
28
|
-
* When the article is initialized it should only have the URL
|
29
|
-
* You can then call Builder which will poll the webservice and grab all the tags
|
30
|
-
2. Article
|
31
|
-
* has a URL
|
32
|
-
* has a list of tags
|
33
|
-
* utilizes builder to actually poll teh article and return the tags
|
34
|
-
3. Builder
|
35
|
-
* accepts a url
|
36
|
-
* returns an array of tags
|
37
|
-
|
38
|
-
## Algorythm
|
39
|
-
* []
|
40
|
-
* Tweet.new(link)
|
41
|
-
* Tweet.add tag
|
42
|
-
* Tweet.add will check if the tweet will be too long with the new tag included
|
43
|
-
* next
|
44
|
-
* tweet add or Tweet.new again
|
45
|
-
|
data/awl_tags_twitter.gemspec
CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_runtime_dependency 'commander', '~> 4.3'
|
23
23
|
spec.add_runtime_dependency 'contracts', '~> 0.12'
|
24
24
|
spec.add_runtime_dependency 'terminal-table', '~> 1.5'
|
25
|
+
spec.add_runtime_dependency 'twitter', '~> 5.16'
|
25
26
|
|
26
27
|
spec.add_development_dependency 'bundler', '~> 1.7'
|
27
28
|
spec.add_development_dependency 'rspec', '~> 3.2'
|
data/bin/awl_tags_twitter
CHANGED
@@ -4,25 +4,12 @@ require 'rubygems'
|
|
4
4
|
require 'commander/import'
|
5
5
|
require 'scraper'
|
6
6
|
require 'terminal-table'
|
7
|
+
require 'twitter_client'
|
7
8
|
require 'awl_tags_twitter/version'
|
8
9
|
|
9
10
|
program :version, AwlTagsTwitter::VERSION
|
10
11
|
program :description, 'Grab tags from posts and tweet them out'
|
11
12
|
|
12
|
-
command :post do |c|
|
13
|
-
c.syntax = 'awl_tags_twitter post [options]'
|
14
|
-
c.summary = ''
|
15
|
-
c.description = ''
|
16
|
-
c.example 'description', 'command example'
|
17
|
-
c.option '--some-switch', 'Some switch that does something'
|
18
|
-
c.action do # |args, options|
|
19
|
-
scrapper = Scraper.new
|
20
|
-
scrapper.some = 'hello'
|
21
|
-
|
22
|
-
puts scrapper.what
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
13
|
command :list do |c|
|
27
14
|
c.syntax = 'awl_tags_twitter list'
|
28
15
|
c.summary = 'List current posts and their tags'
|
@@ -33,32 +20,89 @@ command :list do |c|
|
|
33
20
|
c.option '--basic', 'Display posts with tags'
|
34
21
|
c.option '--complex', 'Display posts with tags split between posts'
|
35
22
|
c.action do |_args, options|
|
36
|
-
|
23
|
+
scraper = Scraper.new
|
24
|
+
scraper.retrieve_posts
|
37
25
|
if options.basic
|
38
|
-
scraper
|
39
|
-
scraper.retrieve_posts
|
26
|
+
scraper.subtract_cache
|
40
27
|
rows = scraper.articles.map { |a| [a.link, a.tags] }
|
41
|
-
table = Terminal::Table.new rows: rows
|
42
|
-
puts table
|
43
28
|
elsif options.complex
|
44
|
-
scraper
|
45
|
-
scraper.
|
29
|
+
scraper.subtract_cache
|
30
|
+
scraper.articles.map(&:build_tweets)
|
46
31
|
rows = scraper.articles.map { |a| [a.link, a.tags, a.tweets] }
|
47
|
-
table = Terminal::Table.new rows: rows
|
48
|
-
puts table
|
49
32
|
else
|
50
33
|
fail 'provide --basic or --complex'
|
51
34
|
end
|
35
|
+
tracker = Tracker.new
|
36
|
+
tracker.read_articles
|
37
|
+
tracker.articles << scraper.articles.map(&:link)
|
38
|
+
tracker.articles.flatten!
|
39
|
+
tracker.write_articles
|
40
|
+
|
41
|
+
table = Terminal::Table.new rows: rows
|
42
|
+
puts table
|
52
43
|
end
|
53
44
|
end
|
54
45
|
|
55
46
|
command :'cache-all' do |c|
|
56
47
|
c.syntax = 'awl_tags_twitter cache-all [options]'
|
57
|
-
c.summary = ''
|
58
|
-
c.description = ''
|
59
|
-
|
60
|
-
c.
|
61
|
-
c.
|
62
|
-
|
48
|
+
c.summary = 'Cache all existing articles'
|
49
|
+
c.description = 'This method will call the AWL and save all files to disk.'\
|
50
|
+
'You can use this if there is an issue while attempting to publish a tweet.'
|
51
|
+
c.example 'default', 'awl_tags_twitter cache-all'
|
52
|
+
c.example 'dry-run', 'awl_tags_twitter cache-all --dry-run'
|
53
|
+
c.option '--dry', 'Print which articles would get saved, but don\'t save them'
|
54
|
+
c.action do |_args, options|
|
55
|
+
scraper = Scraper.new
|
56
|
+
scraper.retrieve_posts
|
57
|
+
scraper.subtract_cache
|
58
|
+
rows = scraper.articles.map { |a| [a.link, a.tags] }
|
59
|
+
tracker = Tracker.new
|
60
|
+
tracker.read_articles
|
61
|
+
tracker.articles << scraper.articles.map(&:link)
|
62
|
+
tracker.articles.flatten!
|
63
|
+
tracker.write_articles unless options.dry
|
64
|
+
|
65
|
+
table = Terminal::Table.new rows: rows
|
66
|
+
puts table
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
command :tweet do |c|
|
71
|
+
c.syntax = 'awl_tags_twitter tweet'
|
72
|
+
c.summary = 'tweet out any untweeted post.'
|
73
|
+
c.description = 'Grabs a list of all the posts which haven\'t been tweeted' \
|
74
|
+
'then builds the tweets, and tweets them for you'
|
75
|
+
c.example 'default', 'awl_tags_twitter tweet'
|
76
|
+
c.example 'dry', 'awl_tags_twitter tweet --dry'
|
77
|
+
c.option '--dry', 'Display what tweets would be sent out'
|
78
|
+
c.option '--config STRING', 'Path to the configuration file'
|
79
|
+
c.action do |_args, options|
|
80
|
+
credentials = JSON.parse(File.read(options.config))
|
81
|
+
twitter_client = TwitterClient.new(credentials)
|
82
|
+
fail 'please pass a configuration file' unless options.config
|
83
|
+
p "loading with Config #{options.config}"
|
84
|
+
scraper = Scraper.new
|
85
|
+
scraper.retrieve_posts
|
86
|
+
scraper.subtract_cache
|
87
|
+
scraper.articles.map(&:build_tweets)
|
88
|
+
tracker = Tracker.new
|
89
|
+
tracker.read_articles
|
90
|
+
tracker.articles << scraper.articles.map(&:link)
|
91
|
+
tracker.articles.flatten!
|
92
|
+
rows = scraper.articles.map { |a| [a.tweets] }
|
93
|
+
|
94
|
+
unless options.dry
|
95
|
+
scraper.articles.each do |a|
|
96
|
+
a.tweets.each do |t|
|
97
|
+
twitter_client.update(t)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# push out them tweets
|
102
|
+
tracker.write_articles
|
103
|
+
end
|
104
|
+
|
105
|
+
table = Terminal::Table.new rows: rows
|
106
|
+
puts table
|
63
107
|
end
|
64
108
|
end
|
data/lib/article.rb
CHANGED
@@ -46,9 +46,9 @@ class Article
|
|
46
46
|
|
47
47
|
# Filters finds the link inside the .g-tag-box div, pulls the name, then makes
|
48
48
|
# the resulting string uppercase.
|
49
|
-
def filter_tags(
|
49
|
+
def filter_tags(document)
|
50
50
|
# Filter down and get the tags.
|
51
|
-
@tags =
|
51
|
+
@tags = document.css(TAG_CSS).map(&:children).map(&:text)
|
52
52
|
end
|
53
53
|
|
54
54
|
# Opens @link, then parses using Nokogiri
|
data/lib/scraper.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
require 'nokogiri'
|
2
|
-
require 'rss'
|
3
1
|
require 'article'
|
4
2
|
require 'contracts'
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'rss'
|
5
|
+
require 'tracker'
|
5
6
|
|
6
7
|
# Class for handling RSS feed to grab posts
|
7
8
|
class Scraper
|
@@ -30,6 +31,15 @@ class Scraper
|
|
30
31
|
@articles << Article.new(link)
|
31
32
|
end
|
32
33
|
|
34
|
+
# TODO: Only grab the tags for articles that haven't already be tweeted
|
33
35
|
@articles.map(&:retrieve_tags)
|
34
36
|
end
|
37
|
+
|
38
|
+
Contract C::None => C::ArrayOf[Article]
|
39
|
+
# Subtrack saved artciles from the list of articles
|
40
|
+
def subtract_cache
|
41
|
+
tracker = Tracker.new
|
42
|
+
tracker.read_articles
|
43
|
+
@articles.delete_if { |x| tracker.articles.include?(x.link) }
|
44
|
+
end
|
35
45
|
end
|
data/lib/tracker.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'contracts'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
# Track previous posts in ./tmp/articles.json
|
5
|
+
class Tracker
|
6
|
+
include Contracts::Core
|
7
|
+
|
8
|
+
attr_accessor :articles
|
9
|
+
|
10
|
+
# Short cut for Contract
|
11
|
+
C = Contracts
|
12
|
+
|
13
|
+
Contract C::None => C::ArrayOf[String]
|
14
|
+
# reads articles from the ./tmp/articles.json file
|
15
|
+
def read_articles
|
16
|
+
file = JSON.load(File.read("#{Dir.home}/awl_articles.json"))
|
17
|
+
@articles = file['articles']
|
18
|
+
|
19
|
+
rescue JSON::ParserError
|
20
|
+
@articles = []
|
21
|
+
rescue Errno::ENOENT
|
22
|
+
@articles = []
|
23
|
+
end
|
24
|
+
|
25
|
+
Contract C::None => C::Num
|
26
|
+
# writes articles from the ./tmp/articles.json file
|
27
|
+
def write_articles
|
28
|
+
f = File.new("#{Dir.home}/.awl_articles.json", 'w')
|
29
|
+
f.write "{ \"articles\": #{@articles} }"
|
30
|
+
end
|
31
|
+
end
|
data/lib/tweet.rb
CHANGED
@@ -14,15 +14,15 @@ class Tweet
|
|
14
14
|
Contract String => String
|
15
15
|
def initialize(link)
|
16
16
|
@link = link
|
17
|
-
@post = @link
|
17
|
+
@post = "| #{@link}"
|
18
18
|
end
|
19
19
|
|
20
20
|
Contract String => String
|
21
21
|
# Add tag to @post
|
22
22
|
def add(tag)
|
23
|
-
temp_post = "#{tag}
|
23
|
+
temp_post = "| #{tag} #{@post}"
|
24
24
|
if temp_post.length <= 140
|
25
|
-
@post =
|
25
|
+
@post = "| #{tag} #{@post}"
|
26
26
|
else
|
27
27
|
fail Tweet::TagTooLong
|
28
28
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'contracts'
|
2
|
+
require 'twitter'
|
3
|
+
|
4
|
+
# Establishes the Twitter client
|
5
|
+
class TwitterClient
|
6
|
+
include Contracts::Core
|
7
|
+
|
8
|
+
# Shortcut for contracts
|
9
|
+
C = Contracts
|
10
|
+
|
11
|
+
Contract Hash => nil
|
12
|
+
def initialize(credentials)
|
13
|
+
# @config = {
|
14
|
+
# consumer_key: '7Jw0Oc7ZVO9NHY5Z5ieYB91Rs',
|
15
|
+
# consumer_secret: 'hjKJVdd2ikwHdD8SMJjDQQOxxw8FmhI22s3oGXtR7u3OllcDqf',
|
16
|
+
# access_token: '794719566966333440-dR7EPJfd6wR5Wc0nhSR1yGZfKmrqPpI',
|
17
|
+
# access_token_secret: 'YWwWVFhRRx84NH2VxjyxnUIiyeT2tEZZiBb8wjQ72ARRX'
|
18
|
+
# }
|
19
|
+
@client = Twitter::REST::Client.new(credentials)
|
20
|
+
fail 'Unable to load your credentials' unless @client.credentials?
|
21
|
+
end
|
22
|
+
|
23
|
+
Contract String => nil
|
24
|
+
# Wrapper for Twitter::Rest::Client.update with retries if too many requests
|
25
|
+
def update(post)
|
26
|
+
@client.update(post)
|
27
|
+
rescue Twitter::Error::TooManyRequests => error
|
28
|
+
# NOTE: Your process could go to sleep for up to 15 minutes but if you
|
29
|
+
# retry any sooner, it will almost certainly fail with the same exception.
|
30
|
+
sleep error.rate_limit.reset_in + 1
|
31
|
+
retry
|
32
|
+
end
|
33
|
+
end
|
data/spec/article_spec.rb
CHANGED
@@ -65,10 +65,10 @@ RSpec.describe Article do
|
|
65
65
|
end
|
66
66
|
|
67
67
|
context 'when there is only a few tags' do
|
68
|
-
let(:tags) {
|
68
|
+
let(:tags) { %w(foo bar) }
|
69
69
|
|
70
70
|
it 'returns an array of tweets' do
|
71
|
-
expect(article.build_tweets.first.post).to eq("#{tags.first} | #{link}")
|
71
|
+
expect(article.build_tweets.first.post).to eq("| #{tags.last} | #{tags.first} | #{link}")
|
72
72
|
end
|
73
73
|
it 'returns only one tweet' do
|
74
74
|
expect(article.build_tweets.count).to eq(1)
|
@@ -98,7 +98,7 @@ RSpec.describe Article do
|
|
98
98
|
it 'returns the array of tweets' do
|
99
99
|
article.build_tweets
|
100
100
|
|
101
|
-
expect(article.tweets).to eq(["#{tags.first} | #{link}"])
|
101
|
+
expect(article.tweets).to eq(["| #{tags.first} | #{link}"])
|
102
102
|
end
|
103
103
|
end
|
104
104
|
end
|
data/spec/scraper_spec.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
require 'scraper'
|
2
2
|
|
3
3
|
RSpec.describe Scraper do
|
4
|
-
|
5
|
-
let(:scraper) { Scraper.new }
|
4
|
+
let(:scraper) { Scraper.new }
|
6
5
|
|
6
|
+
context '#retrieve_posts' do
|
7
7
|
it 'responsed', :vcr do
|
8
8
|
expect(scraper).to respond_to(:retrieve_posts)
|
9
9
|
end
|
10
|
-
|
11
10
|
it 'returns an arrays', :vcr do
|
12
11
|
expect(scraper.retrieve_posts).to be_kind_of(Array)
|
13
12
|
end
|
@@ -21,7 +20,39 @@ RSpec.describe Scraper do
|
|
21
20
|
end
|
22
21
|
end
|
23
22
|
|
24
|
-
context '#
|
23
|
+
context '#articles' do
|
25
24
|
it { should respond_to(:articles) }
|
26
25
|
end
|
26
|
+
|
27
|
+
context '#subtract_cache' do
|
28
|
+
let(:article_1) { Article.new('http://domain.com/1') }
|
29
|
+
let(:article_2) { Article.new('http://domain.com/2') }
|
30
|
+
let(:double) { ['foo'] }
|
31
|
+
|
32
|
+
context 'when there are previous articles' do
|
33
|
+
before do
|
34
|
+
allow_any_instance_of(Tracker).to receive(:articles).and_return(['http://domain.com/1'])
|
35
|
+
allow_any_instance_of(Tracker).to receive(:read_articles).and_return(['http://domain.com/1'])
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'does not return the previous articles', :vcr do
|
39
|
+
scraper.instance_variable_set(:@articles, [article_1, article_2])
|
40
|
+
scraper.subtract_cache
|
41
|
+
expect(scraper.articles.map(&:link)).to eq(['http://domain.com/2'])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when there are no previous posts' do
|
46
|
+
before do
|
47
|
+
allow_any_instance_of(Tracker).to receive(:articles).and_return([])
|
48
|
+
allow_any_instance_of(Tracker).to receive(:read_articles).and_return([])
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'returns all posts' do
|
52
|
+
scraper.instance_variable_set(:@articles, [article_1, article_2])
|
53
|
+
scraper.subtract_cache
|
54
|
+
expect(scraper.articles.map(&:link)).to eq(['http://domain.com/1', 'http://domain.com/2'])
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
27
58
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'tracker'
|
2
|
+
|
3
|
+
RSpec.describe Tracker do
|
4
|
+
let(:tracker) { Tracker.new }
|
5
|
+
let(:data) { '{ "articles" : [ "https://domain.com/123456" ] }' }
|
6
|
+
|
7
|
+
before do
|
8
|
+
allow(File).to receive(:read).and_return(data)
|
9
|
+
end
|
10
|
+
|
11
|
+
context '#articles' do
|
12
|
+
context 'when the file is populated' do
|
13
|
+
it 'returns an array with urls' do
|
14
|
+
expect(tracker.read_articles).to eq(['https://domain.com/123456'])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'when the file does not contain JSON' do
|
19
|
+
let(:data) { ' { "articles": "blah" : "foo" } ' }
|
20
|
+
|
21
|
+
it 'returns an empty array' do
|
22
|
+
expect(tracker.read_articles).to eq([])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'when the file does not exist' do
|
27
|
+
let(:data) { '{ "articles": [] }' }
|
28
|
+
|
29
|
+
before do
|
30
|
+
expect(File).to receive(:read).once.and_raise(Errno::ENOENT)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'returns an empty array' do
|
34
|
+
expect(tracker.read_articles).to eq([])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context '#read_articles' do
|
40
|
+
it 'returns an array of articles' do
|
41
|
+
expect(tracker.read_articles).to eq(['https://domain.com/123456'])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context '#write_articles' do
|
46
|
+
it { is_expected.to respond_to(:write_articles) }
|
47
|
+
|
48
|
+
context 'when the JSON is valid' do
|
49
|
+
let(:articles) { ['https://domain.com/123456'] }
|
50
|
+
|
51
|
+
before do
|
52
|
+
expect_any_instance_of(File).to receive(:write).and_return(47)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'it writes the JSON to file' do
|
56
|
+
tracker.instance_variable_set(:@articles, articles)
|
57
|
+
tracker.write_articles
|
58
|
+
expect(tracker.read_articles).to eq(articles)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/spec/tweet_spec.rb
CHANGED
@@ -14,7 +14,7 @@ RSpec.describe Tweet do
|
|
14
14
|
context 'when the tag + @post is < 140' do
|
15
15
|
let(:tag) { 'foo' }
|
16
16
|
it 'is added' do
|
17
|
-
expect(tweet.add(tag)).to eq("#{tag} | #{link}")
|
17
|
+
expect(tweet.add(tag)).to eq("| #{tag} | #{link}")
|
18
18
|
end
|
19
19
|
end
|
20
20
|
context 'when the tag + @post is > 140' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: awl_tags_twitter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jack Ellis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-11-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '1.5'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: twitter
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '5.16'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '5.16'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: bundler
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -256,14 +270,17 @@ files:
|
|
256
270
|
- lib/article.rb
|
257
271
|
- lib/awl_tags_twitter/version.rb
|
258
272
|
- lib/scraper.rb
|
273
|
+
- lib/tracker.rb
|
259
274
|
- lib/tweet.rb
|
260
275
|
- lib/tweet/tag_too_long.rb
|
261
|
-
- lib/
|
276
|
+
- lib/twitter_client.rb
|
262
277
|
- spec/.txt
|
263
278
|
- spec/article_spec.rb
|
264
279
|
- spec/scraper_spec.rb
|
265
280
|
- spec/spec_helper.rb
|
281
|
+
- spec/tracker_spec.rb
|
266
282
|
- spec/tweet_spec.rb
|
283
|
+
- spec/twitter_client.rb
|
267
284
|
- spec/version_spec.rb
|
268
285
|
homepage: https://github.com/ellisandy
|
269
286
|
licenses:
|
@@ -294,6 +311,8 @@ test_files:
|
|
294
311
|
- spec/article_spec.rb
|
295
312
|
- spec/scraper_spec.rb
|
296
313
|
- spec/spec_helper.rb
|
314
|
+
- spec/tracker_spec.rb
|
297
315
|
- spec/tweet_spec.rb
|
316
|
+
- spec/twitter_client.rb
|
298
317
|
- spec/version_spec.rb
|
299
318
|
has_rdoc:
|