tweetomator 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 825073922927da43ac05a2c1a35dcd873121991c
4
+ data.tar.gz: 0d1d48bf51e633eec1ad54cd6a3866497650e5ed
5
+ SHA512:
6
+ metadata.gz: 99538aab29a3f37c9747c3010658858d121c92dfe7c9522d8e1f71e04a9b6b773bcea4790c066403dabfe85cb9d80be9cba9d3ac70b1b0863da6d3a97c3d92f7
7
+ data.tar.gz: 375e71144fcce36676bb8faf358d873825b8bc73cad01384bea4334f0781bbf0c86119ee58dcdb4151e585b813356c29deb4642d82ca2f1a2ad5cb93de180020
data/.gitignore ADDED
@@ -0,0 +1,69 @@
1
+ # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion
2
+
3
+ *.iml
4
+
5
+ ## Directory-based project format:
6
+ .idea/
7
+ # if you remove the above rule, at least ignore the following:
8
+
9
+ # User-specific stuff:
10
+ # .idea/workspace.xml
11
+ # .idea/tasks.xml
12
+ # .idea/dictionaries
13
+
14
+ # Sensitive or high-churn files:
15
+ # .idea/dataSources.ids
16
+ # .idea/dataSources.xml
17
+ # .idea/sqlDataSources.xml
18
+ # .idea/dynamic.xml
19
+ # .idea/uiDesigner.xml
20
+
21
+ # Gradle:
22
+ # .idea/gradle.xml
23
+ # .idea/libraries
24
+
25
+ # Mongo Explorer plugin:
26
+ # .idea/mongoSettings.xml
27
+
28
+ ## File-based project format:
29
+ *.ipr
30
+ *.iws
31
+
32
+ ## Plugin-specific files:
33
+
34
+ # IntelliJ
35
+ /out/
36
+
37
+ # mpeltonen/sbt-idea plugin
38
+ .idea_modules/
39
+
40
+ # JIRA plugin
41
+ atlassian-ide-plugin.xml
42
+
43
+ # Crashlytics plugin (for Android Studio and IntelliJ)
44
+ com_crashlytics_export_strings.xml
45
+ crashlytics.properties
46
+ crashlytics-build.properties
47
+
48
+ *.gem
49
+ *.rbc
50
+ .bundle
51
+ .config
52
+ .yardoc
53
+ Gemfile.lock
54
+ InstalledFiles
55
+ _yardoc
56
+ coverage
57
+ doc/
58
+ lib/bundler/man
59
+ pkg
60
+ rdoc
61
+ spec/reports
62
+ test/tmp
63
+ test/version_tmp
64
+ tmp
65
+ *.bundle
66
+ *.so
67
+ *.o
68
+ *.a
69
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in tweetomator.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,53 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ tweetomator (1.0.0)
5
+ flickraw
6
+ rufus-scheduler
7
+ twitter
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ addressable (2.3.7)
13
+ buftok (0.2.0)
14
+ equalizer (0.0.9)
15
+ faraday (0.9.0)
16
+ multipart-post (>= 1.2, < 3)
17
+ flickraw (0.9.8)
18
+ http (0.6.3)
19
+ http_parser.rb (~> 0.6.0)
20
+ http_parser.rb (0.6.0)
21
+ json (1.8.2)
22
+ memoizable (0.4.2)
23
+ thread_safe (~> 0.3, >= 0.3.1)
24
+ minitest (5.5.1)
25
+ multipart-post (2.0.0)
26
+ naught (1.0.0)
27
+ rake (10.4.2)
28
+ rufus-scheduler (3.0.9)
29
+ tzinfo
30
+ simple_oauth (0.3.0)
31
+ thread_safe (0.3.5)
32
+ twitter (5.13.0)
33
+ addressable (~> 2.3)
34
+ buftok (~> 0.2.0)
35
+ equalizer (~> 0.0.9)
36
+ faraday (~> 0.9.0)
37
+ http (~> 0.6.0)
38
+ http_parser.rb (~> 0.6.0)
39
+ json (~> 1.8)
40
+ memoizable (~> 0.4.0)
41
+ naught (~> 1.0)
42
+ simple_oauth (~> 0.3.0)
43
+ tzinfo (1.2.2)
44
+ thread_safe (~> 0.1)
45
+
46
+ PLATFORMS
47
+ ruby
48
+
49
+ DEPENDENCIES
50
+ bundler (~> 1.6)
51
+ minitest
52
+ rake
53
+ tweetomator!
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Nat Young
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # Tweetomator
2
+
3
+ Investigating the principal curvatures of the twittersphere.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'tweetomator'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install tweetomator
18
+
19
+ ## Usage
20
+
21
+ Create a new instance of each config class in config/config.rb
22
+
23
+ e.g.
24
+
25
+ twitter_config = TwitterConfig.new([...])
26
+ flickr_config = FlickrConfig.new([...])
27
+ tweetomator_config = TweetomatorConfig.new(twitter, flickr, [...])
28
+ tweetomator = Tweetomator.new(tweetomator_config)
29
+ tweetomator.run
30
+
31
+ ## Contributing
32
+
33
+ 1. Fork it ( https://github.com/[my-github-username]/tweetomator/fork )
34
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
35
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
36
+ 4. Push to the branch (`git push origin my-new-feature`)
37
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+ require 'minitest/autorun'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << 'test'
7
+ t.pattern = 'test/**/*_test.rb'
8
+ t.verbose = true
9
+ end
@@ -0,0 +1,21 @@
1
+ require 'flickraw'
2
+
3
+ class FlickrClient
4
+ module Fixed
5
+ MIN_UPLOAD_DATE = 1357028420
6
+ freeze
7
+ end
8
+
9
+ def initialize(flickr_config)
10
+ FlickRaw.api_key = flickr_config.api_key
11
+ FlickRaw.shared_secret = flickr_config.shared_secret
12
+ end
13
+
14
+ def uri(uri)
15
+ FlickRaw.url(uri)
16
+ end
17
+
18
+ def search(query)
19
+ flickr.photos.search(tags: query, min_upload_date: Fixed::MIN_UPLOAD_DATE)
20
+ end
21
+ end
@@ -0,0 +1,32 @@
1
+ class TwitterClient
2
+ def initialize(twitter_config)
3
+ @rest_client = Twitter::REST::Client.new do |config|
4
+ config.consumer_key = twitter_config.consumer_key
5
+ config.consumer_secret = twitter_config.consumer_secret
6
+ config.access_token = twitter_config.access_token
7
+ config.access_token_secret = twitter_config.access_token_secret
8
+ end
9
+ @username = twitter_config.username
10
+ end
11
+
12
+ def random_follower_of_random_follower
13
+ follower = @rest_client.followers.attrs[:users].sample[:screen_name]
14
+ @rest_client.friend_ids(follower).attrs[:ids].sample
15
+ end
16
+
17
+ def update_with_media(text, image_file)
18
+ @rest_client.update_with_media(text, image_file)
19
+ end
20
+
21
+ def update(text)
22
+ @rest_client.update(text)
23
+ end
24
+
25
+ def search(query)
26
+ @rest_client.search("#{query} -rt -from:#{@username}", { lang: 'en' }).first.text
27
+ end
28
+
29
+ def follow(user)
30
+ @rest_client.follow(user)
31
+ end
32
+ end
data/lib/composer.rb ADDED
@@ -0,0 +1,54 @@
1
+ require 'cgi'
2
+ require_relative 'tweet'
3
+
4
+ class Composer
5
+ def initialize(tweet_finder, emoji_finder, blacklist, twitter_client, max_length)
6
+ @tweet_finder = tweet_finder
7
+ @emoji_finder = emoji_finder
8
+ @blacklist = blacklist
9
+ @twitter_client = twitter_client
10
+ @max_length = max_length
11
+ end
12
+
13
+ def compose
14
+ tweets = @tweet_finder.find_tweets
15
+ tweets = tweets.map { |t| normalize(t) }
16
+ hashtag = @tweet_finder.find_random_word(tweets.sample)
17
+ emoji = @emoji_finder.find
18
+ text = tweets.join([', ', ' - ', '! '].sample)
19
+ text = filter(text)
20
+ text = trim(text, hashtag.length)
21
+ text = replace_a_word(text.split.sample, text)
22
+ text = replace_a_word(emoji, text)
23
+ Tweet.new(text.capitalize, hashtag, @twitter_client)
24
+ end
25
+
26
+ private
27
+
28
+ def normalize(tweet)
29
+ CGI.unescapeHTML(tweet.gsub(/(@([^\s])+|http([^\s])+|([^\s])+\/([^\s])+|)/, ''))
30
+ .gsub(/\s+/, ' ')
31
+ .strip
32
+ .downcase
33
+ .gsub(/[^[:word:]\s]/, '')
34
+ end
35
+
36
+ def filter(tweet)
37
+ tweet.split.reject { |w| @blacklist.include?(w.downcase) }.join(' ')
38
+ end
39
+
40
+ def replace_a_word(replacement, target)
41
+ split = target.split
42
+ out = split.select { |w| w.length >= replacement.length }.sample
43
+ split.map { |w| w == out ? replacement : w }.join(' ')
44
+ end
45
+
46
+ def trim(tweet, hashtag_length)
47
+ if tweet.size > (@max_length - (hashtag_length > 0 ? hashtag_length + 1 : 0))
48
+ split = tweet.split
49
+ split.delete_at(split.length - 1)
50
+ return trim(split.join(' '), hashtag_length)
51
+ end
52
+ tweet
53
+ end
54
+ end
@@ -0,0 +1,50 @@
1
+ module Validatable
2
+ def valid?
3
+ self.instance_variables.none? do |v|
4
+ attr = instance_variable_get(v)
5
+ attr.class.included_modules.include?(Validatable) ? !attr.valid? : attr == nil
6
+ end
7
+ end
8
+ end
9
+
10
+ class TwitterConfig
11
+ include Validatable
12
+
13
+ attr_reader :consumer_key, :consumer_secret, :access_token, :access_token_secret,
14
+ :username, :tweet_max_length
15
+
16
+ def initialize(consumer_key, consumer_secret, access_token, access_token_secret, username, tweet_max_length)
17
+ @consumer_key = consumer_key
18
+ @consumer_secret = consumer_secret
19
+ @access_token = access_token
20
+ @access_token_secret = access_token_secret
21
+ @username = username
22
+ @tweet_max_length = tweet_max_length
23
+ end
24
+ end
25
+
26
+ class FlickrConfig
27
+ include Validatable
28
+
29
+ attr_reader :api_key, :shared_secret
30
+
31
+ def initialize(api_key, shared_secret)
32
+ @api_key = api_key
33
+ @shared_secret = shared_secret
34
+ end
35
+ end
36
+
37
+ class TweetomatorConfig
38
+ include Validatable
39
+
40
+ attr_reader :twitter_config, :flickr_config, :topics, :blacklist, :stop_words, :delay_in_seconds
41
+
42
+ def initialize(twitter_config, flickr_config, topics, blacklist, stop_words, delay_in_seconds)
43
+ @twitter_config = twitter_config
44
+ @flickr_config = flickr_config
45
+ @topics = topics
46
+ @blacklist = blacklist
47
+ @stop_words = stop_words
48
+ @delay_in_seconds = delay_in_seconds
49
+ end
50
+ end
@@ -0,0 +1,11 @@
1
+ require 'open-uri'
2
+
3
+ class EmojiFinder
4
+ def find
5
+ [(127744..127775),
6
+ (127792..127855),
7
+ (127872..127887),
8
+ (127904..127935),
9
+ (128000..128239)].map { |r| Array(r) }.inject(:+).sample.chr('utf-8')
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ class FlickrFindr
2
+ def initialize(flickr_client)
3
+ @flickr_client = flickr_client
4
+ end
5
+
6
+ def find(query)
7
+ results = @flickr_client.search(query)
8
+ @flickr_client.uri(results.to_a.sample)
9
+ end
10
+ end
@@ -0,0 +1,29 @@
1
+ class TweetFinder
2
+ def initialize(client, topics, stop_words)
3
+ @client = client
4
+ @topics = topics
5
+ @stop_words = stop_words
6
+ end
7
+
8
+ def find_tweets
9
+ @topics.reduce([]) do |t, topic|
10
+ t << Thread.new(topic) { |topic| find_tweet(topic) }
11
+ end.each { |t| t.join }.map { |t| t.value }
12
+ end
13
+
14
+ def find_tweet(query)
15
+ @client.search(query)
16
+ end
17
+
18
+ def find_random_word(query)
19
+ term = extract_one_word(query)
20
+ tweet = find_tweet(term)
21
+ extract_one_word(tweet)
22
+ end
23
+
24
+ private
25
+
26
+ def extract_one_word(tweet)
27
+ tweet.split.reject { |w| /[^A-Za-z0-9]/.match(w.strip) != nil || @stop_words.include?(w.strip) }.sample
28
+ end
29
+ end
@@ -0,0 +1,12 @@
1
+ require 'open-uri'
2
+
3
+ class Downloader
4
+ def download(uri, local_path)
5
+ File.open(local_path, 'wb') do |saved_file|
6
+ open(uri, 'rb') do |read_file|
7
+ saved_file.write(read_file.read)
8
+ end
9
+ end
10
+ local_path
11
+ end
12
+ end
data/lib/tweet.rb ADDED
@@ -0,0 +1,26 @@
1
+ class Tweet
2
+ attr_reader :hashtag
3
+
4
+ def initialize(text, hashtag, twitter_client)
5
+ @text = text
6
+ @hashtag = hashtag
7
+ @twitter_client = twitter_client
8
+ end
9
+
10
+ def post!(image = '')
11
+ if image.length > 0 && File.exists?(image)
12
+ @twitter_client.update_with_media(self.with_hashtag, File.new(image))
13
+ File.delete(image)
14
+ else
15
+ @twitter_client.update(self.with_hashtag)
16
+ end
17
+ end
18
+
19
+ def with_hashtag
20
+ (@hashtag && @hashtag.length > 0) ? "#{@text} ##{@hashtag}" : @text
21
+ end
22
+
23
+ def length
24
+ with_hashtag.length
25
+ end
26
+ end
@@ -0,0 +1,75 @@
1
+ require 'tweetomator/version'
2
+ require 'twitter'
3
+ require 'rufus-scheduler'
4
+ require_relative 'tweet'
5
+ require_relative 'tweetomator'
6
+ require_relative 'composer'
7
+ require_relative 'config/config'
8
+ require_relative 'finders/tweet_finder'
9
+ require_relative 'finders/flickr_findr'
10
+ require_relative 'finders/emoji_finder'
11
+ require_relative 'clients/flickr_client'
12
+ require_relative 'clients/twitter_client'
13
+ require_relative 'io/downloader'
14
+
15
+ class Tweetomator
16
+ def initialize(tweetomator_config)
17
+ if tweetomator_config.valid?
18
+ somebody_set_us_up_the_bot(tweetomator_config)
19
+ else
20
+ raise 'Invalid TweetomatorConfig'
21
+ end
22
+ end
23
+
24
+ def run
25
+ begin
26
+ @scheduler.interval("#{@delay}s") { do_stuff }
27
+ @scheduler.join
28
+ rescue
29
+ retry
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def somebody_set_us_up_the_bot(config)
36
+ @delay = config.delay_in_seconds
37
+ @twitter_client = TwitterClient.new(config.twitter_config)
38
+ @tweet_finder = TweetFinder.new(@twitter_client, config.topics, config.stop_words)
39
+ flickr_client = FlickrClient.new(config.flickr_config)
40
+ @flickr_finder = FlickrFindr.new(flickr_client)
41
+ emoji_finder = EmojiFinder.new
42
+ @composer = Composer.new(@tweet_finder, emoji_finder, config.blacklist, @twitter_client, config.twitter_config.tweet_max_length)
43
+ @downloader = Downloader.new
44
+ @scheduler = Rufus::Scheduler.new
45
+ end
46
+
47
+ def do_stuff
48
+ r = (1..4).to_a.sample
49
+ if r < 3
50
+ tweet_with_image!
51
+ elsif r < 4
52
+ tweet!
53
+ else
54
+ follow!
55
+ end
56
+ end
57
+
58
+ def tweet!
59
+ tweet = @composer.compose
60
+ tweet.post!
61
+ end
62
+
63
+ def tweet_with_image!
64
+ tweet = @composer.compose
65
+ flickr_query = @tweet_finder.find_random_word(tweet.hashtag)
66
+ image_uri = @flickr_finder.find(flickr_query)
67
+ image_local = @downloader.download(image_uri, 'image')
68
+ tweet.post!(image_local)
69
+ end
70
+
71
+ def follow!
72
+ user = @twitter_client.random_follower_of_random_follower
73
+ @twitter_client.follow(user)
74
+ end
75
+ end
@@ -0,0 +1,3 @@
1
+ class Tweetomator
2
+ VERSION = '1.0.0'
3
+ end
@@ -0,0 +1,40 @@
1
+ require 'minitest/autorun'
2
+ require_relative '../../lib/composer'
3
+ require_relative '../../lib/tweetomator'
4
+
5
+ class TestComposer < Minitest::Unit::TestCase
6
+ def setup
7
+ tweet_1 = 'I just backedeyeyeyey Potato Salad on @Kickstarter kck.st/1pLytCe'
8
+ tweet_2 = 'I HAVE NYANED FOR 48.9 SECONDS! http://nyan.cat via @nyannyancat'
9
+ cool_story = "So there I am, in Sri Lanka, formerly Ceylon, at about 3 o'clock in the morning, looking for one thousand brown M&Ms to fill a brandy glass, or Ozzy wouldn't go on stage that night. So, Jeff Beck pops his head 'round the door, and mentions there's a little sweets shop on the edge of town. So - we go. And - it's closed. So there's me, and Keith Moon, and David Crosby, breaking into that little sweets shop, eh. Well, instead of a guard dog, they've got this bloody great big Bengal tiger. I managed to take out the tiger with a can of mace, but the shopkeeper and his son... that's a different story altogether. I had to beat them to death with their own shoes. Nasty business, really, but sure enough I got the M&Ms, and Ozzy went on stage and did a great show."
10
+ mock_emoji_finder = Minitest::Mock.new
11
+ mock_emoji_finder.expect :find, ':trollface:'
12
+ mock_tweet_finder = Minitest::Mock.new
13
+ mock_tweet_finder.expect :find_tweets, [tweet_1, tweet_2, cool_story]
14
+ mock_tweet_finder.expect :find_random_word, 'amazing', [String]
15
+ mock_tweet_client = Minitest::Mock.new
16
+ @blacklist = %w(sri lanka)
17
+ @max_length = 100
18
+ @composer = Composer.new(mock_tweet_finder, mock_emoji_finder, @blacklist, mock_tweet_client, @max_length)
19
+ end
20
+
21
+ def test_that_tweet_is_short_enough
22
+ tweet = @composer.compose
23
+ assert tweet.with_hashtag.length <= @max_length, true
24
+ end
25
+
26
+ def test_that_stop_words_are_removed
27
+ tweet = @composer.compose
28
+ refute tweet.with_hashtag.split.any? { |word| @blacklist.include?(word) }, true
29
+ end
30
+
31
+ def test_that_links_are_removed
32
+ tweet = @composer.compose
33
+ refute tweet.with_hashtag.split.any? { |word| %w(kck.st/1pLytCe http://nyan.cat).include?(word) }, true
34
+ end
35
+
36
+ def test_that_emoji_is_trololo
37
+ tweet = @composer.compose
38
+ assert tweet.with_hashtag.split.any? { |word| word == ':trollface:' }, true
39
+ end
40
+ end
@@ -0,0 +1,16 @@
1
+ require 'minitest/autorun'
2
+ require_relative '../../../lib/finders/flickr_findr'
3
+
4
+ class TestFlickrFindr < Minitest::Unit::TestCase
5
+ def setup
6
+ mock_flickr_client = Minitest::Mock.new
7
+ mock_flickr_client.expect :search, ['http://www.flickr.com/garbage'], [String]
8
+ mock_flickr_client.expect :uri, 'http://www.flickr.com/garbage', [String]
9
+ @finder = FlickrFindr.new(mock_flickr_client)
10
+ end
11
+
12
+ def test_that_it_returns_an_image_path
13
+ path = @finder.find('something')
14
+ assert_equal path, 'http://www.flickr.com/garbage'
15
+ end
16
+ end
@@ -0,0 +1,28 @@
1
+ require 'minitest/autorun'
2
+ require_relative '../../../lib/finders/tweet_finder'
3
+
4
+ class TestTweetFinder < Minitest::Unit::TestCase
5
+ def setup
6
+ mock_search_result = Minitest::Mock.new
7
+ result_1 = 'I just backed Potato Salad on @Kickstarter kck.st/1pLytCe'
8
+ result_2 = 'I am a chicken'
9
+ result_3 = 'And there I was in Sri Lanka, formerly Ceylon'
10
+ mock_search_result.expect :text, result_1
11
+ mock_search_result.expect :text, result_2
12
+ mock_search_result.expect :text, result_3
13
+ mock_client = Minitest::Mock.new
14
+ 3.times { mock_client.expect :search, [mock_search_result], [String, Hash] }
15
+ stop_words = result_1.split + result_2.split + result_3.split
16
+ @finder = TweetFinder.new(mock_client, '@mrnatyoung', ['Trumpets', 'Bookmarks', 'Potato Salads'], stop_words)
17
+ end
18
+
19
+ def test_that_it_finds_a_tweet_per_query
20
+ tweets = @finder.find_tweets
21
+ assert_equal tweets.size, 3
22
+ end
23
+
24
+ def test_stop_words_are_filtered_from_find_random_word
25
+ word = @finder.find_random_word('something')
26
+ assert_equal word, nil
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'tweetomator/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'tweetomator'
8
+ spec.version = Tweetomator::VERSION
9
+ spec.authors = ['Nat Young']
10
+ spec.email = ['nat.young7@gmail.com']
11
+ spec.summary = %q{Twitter automation for the time poor.}
12
+ spec.description = %q{Captivate your twitter audience with a series of interesting tweets and beautiful photos.}
13
+ spec.homepage = 'https://github.com/natyoung/tweetomator'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.6'
22
+ spec.add_development_dependency 'rake'
23
+ spec.add_development_dependency 'minitest'
24
+
25
+ spec.add_runtime_dependency 'flickraw'
26
+ spec.add_runtime_dependency 'twitter'
27
+ spec.add_runtime_dependency 'rufus-scheduler'
28
+ end
metadata ADDED
@@ -0,0 +1,153 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tweetomator
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Nat Young
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-06-01 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.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: flickraw
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: twitter
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rufus-scheduler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Captivate your twitter audience with a series of interesting tweets and
98
+ beautiful photos.
99
+ email:
100
+ - nat.young7@gmail.com
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - .gitignore
106
+ - Gemfile
107
+ - Gemfile.lock
108
+ - LICENSE.txt
109
+ - README.md
110
+ - Rakefile
111
+ - lib/clients/flickr_client.rb
112
+ - lib/clients/twitter_client.rb
113
+ - lib/composer.rb
114
+ - lib/config/config.rb
115
+ - lib/finders/emoji_finder.rb
116
+ - lib/finders/flickr_findr.rb
117
+ - lib/finders/tweet_finder.rb
118
+ - lib/io/downloader.rb
119
+ - lib/tweet.rb
120
+ - lib/tweetomator.rb
121
+ - lib/tweetomator/version.rb
122
+ - test/lib/composer_test.rb
123
+ - test/lib/finders/flickr_findr_test.rb
124
+ - test/lib/finders/tweet_finder_test.rb
125
+ - tweetomator.gemspec
126
+ homepage: https://github.com/natyoung/tweetomator
127
+ licenses:
128
+ - MIT
129
+ metadata: {}
130
+ post_install_message:
131
+ rdoc_options: []
132
+ require_paths:
133
+ - lib
134
+ required_ruby_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ required_rubygems_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - '>='
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ requirements: []
145
+ rubyforge_project:
146
+ rubygems_version: 2.2.2
147
+ signing_key:
148
+ specification_version: 4
149
+ summary: Twitter automation for the time poor.
150
+ test_files:
151
+ - test/lib/composer_test.rb
152
+ - test/lib/finders/flickr_findr_test.rb
153
+ - test/lib/finders/tweet_finder_test.rb