retrobot 0.2.1 → 0.3.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 +4 -4
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/ChangeLog.md +9 -0
- data/Gemfile.lock +25 -15
- data/README.md +6 -4
- data/lib/retrobot.rb +21 -25
- data/lib/retrobot/config.rb +6 -1
- data/lib/retrobot/tweet.rb +39 -0
- data/lib/retrobot/tweet_filters.rb +12 -0
- data/lib/retrobot/tweet_filters/add_in_reply_to_url.rb +58 -0
- data/lib/retrobot/tweet_filters/base.rb +23 -0
- data/lib/retrobot/tweet_filters/remove_atmark.rb +16 -0
- data/lib/retrobot/tweet_filters/retro_days.rb +21 -0
- data/lib/retrobot/tweet_filters/retweet.rb +34 -0
- data/lib/retrobot/tweet_filters/tweet.rb +25 -0
- data/lib/retrobot/tweet_filters/unescape.rb +16 -0
- data/lib/retrobot/version.rb +1 -1
- data/retrobot.example.yml +2 -0
- data/retrobot.gemspec +3 -0
- data/spec/lib/retrobot/tweet_filters_spec.rb +145 -0
- data/spec/lib/retrobot_spec.rb +92 -0
- data/spec/spec_helper.rb +17 -0
- metadata +48 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6a83f05838bf270e208f5e779ccbcd3d0ce814e9
|
|
4
|
+
data.tar.gz: d8cb968b4d3de7c7caba534574f5ebe5e2f0a71f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ca4e4c5d47268cea152c90334ca1fba6c858f3cb279a98b60ea80db948fde6636c044e79d33e308c5b91033ac227497d60812b1c5fc3550c8c6ee5025de8c68a
|
|
7
|
+
data.tar.gz: 2ca8bc2190c7a44493f51523b3aa1c8980e2bad419fd629e3e2f3dc2c378a4a77914e3ce9d3058ac34559cb8f992e3e867d4be485212a8591b319d2f477a0d56
|
data/.rspec
ADDED
data/.travis.yml
ADDED
data/ChangeLog.md
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
# ChangeLog
|
|
2
|
+
## 0.3.0
|
|
3
|
+
- Add `add_in_reply_to` option (Thanks @studio3104)
|
|
4
|
+
- https://github.com/mirakui/retrobot/pull/7
|
|
5
|
+
- Separate bot logics as TweetFilters
|
|
6
|
+
|
|
7
|
+
## 0.2.2
|
|
8
|
+
- Stop supporting Ruby 1.9
|
|
9
|
+
- Add `retweet` option (default: `false`)
|
|
10
|
+
|
|
2
11
|
## 0.2.1
|
|
3
12
|
- Update twitter gem to suppress the deprecation warning from faraday gem
|
|
4
13
|
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
retrobot (0.
|
|
4
|
+
retrobot (0.3.0)
|
|
5
5
|
activesupport (~> 4.0)
|
|
6
6
|
daemons
|
|
7
7
|
get-twitter-oauth-token
|
|
@@ -11,52 +11,62 @@ PATH
|
|
|
11
11
|
GEM
|
|
12
12
|
remote: https://rubygems.org/
|
|
13
13
|
specs:
|
|
14
|
-
activesupport (4.
|
|
14
|
+
activesupport (4.1.1)
|
|
15
15
|
i18n (~> 0.6, >= 0.6.9)
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
json (~> 1.7, >= 1.7.7)
|
|
17
|
+
minitest (~> 5.1)
|
|
18
18
|
thread_safe (~> 0.1)
|
|
19
|
-
tzinfo (~>
|
|
19
|
+
tzinfo (~> 1.1)
|
|
20
20
|
addressable (2.3.6)
|
|
21
|
-
atomic (1.1.16)
|
|
22
21
|
buftok (0.2.0)
|
|
23
22
|
daemons (1.1.9)
|
|
23
|
+
diff-lcs (1.2.5)
|
|
24
24
|
equalizer (0.0.9)
|
|
25
25
|
faraday (0.9.0)
|
|
26
26
|
multipart-post (>= 1.2, < 3)
|
|
27
27
|
get-twitter-oauth-token (1.1.0)
|
|
28
28
|
oauth
|
|
29
|
-
http (0.
|
|
30
|
-
http_parser.rb
|
|
29
|
+
http (0.6.1)
|
|
30
|
+
http_parser.rb (~> 0.6.0)
|
|
31
31
|
http_parser.rb (0.6.0)
|
|
32
32
|
i18n (0.6.9)
|
|
33
33
|
json (1.8.1)
|
|
34
34
|
memoizable (0.4.2)
|
|
35
35
|
thread_safe (~> 0.3, >= 0.3.1)
|
|
36
|
-
minitest (
|
|
37
|
-
multi_json (1.9.2)
|
|
36
|
+
minitest (5.3.4)
|
|
38
37
|
multipart-post (2.0.0)
|
|
39
38
|
naught (1.0.0)
|
|
40
39
|
oauth (0.4.7)
|
|
41
40
|
retryable (1.3.5)
|
|
41
|
+
rspec (2.99.0)
|
|
42
|
+
rspec-core (~> 2.99.0)
|
|
43
|
+
rspec-expectations (~> 2.99.0)
|
|
44
|
+
rspec-mocks (~> 2.99.0)
|
|
45
|
+
rspec-core (2.99.0)
|
|
46
|
+
rspec-expectations (2.99.0)
|
|
47
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
|
48
|
+
rspec-mocks (2.99.1)
|
|
42
49
|
simple_oauth (0.2.0)
|
|
43
|
-
thread_safe (0.3.
|
|
44
|
-
|
|
45
|
-
twitter (5.
|
|
50
|
+
thread_safe (0.3.4)
|
|
51
|
+
timecop (0.7.1)
|
|
52
|
+
twitter (5.10.0)
|
|
46
53
|
addressable (~> 2.3)
|
|
47
54
|
buftok (~> 0.2.0)
|
|
48
55
|
equalizer (~> 0.0.9)
|
|
49
56
|
faraday (~> 0.9.0)
|
|
50
|
-
http (~> 0.
|
|
57
|
+
http (~> 0.6.0)
|
|
51
58
|
http_parser.rb (~> 0.6.0)
|
|
52
59
|
json (~> 1.8)
|
|
53
60
|
memoizable (~> 0.4.0)
|
|
54
61
|
naught (~> 1.0)
|
|
55
62
|
simple_oauth (~> 0.2.0)
|
|
56
|
-
tzinfo (
|
|
63
|
+
tzinfo (1.2.1)
|
|
64
|
+
thread_safe (~> 0.1)
|
|
57
65
|
|
|
58
66
|
PLATFORMS
|
|
59
67
|
ruby
|
|
60
68
|
|
|
61
69
|
DEPENDENCIES
|
|
62
70
|
retrobot!
|
|
71
|
+
rspec (= 2.99)
|
|
72
|
+
timecop
|
data/README.md
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
[](https://travis-ci.org/mirakui/retrobot)
|
|
2
|
+
|
|
1
3
|
retrobot
|
|
2
4
|
=============
|
|
3
5
|
Retrobot is a twitter-bot engine that working at [mirakui_retro](https://twitter.com/mirakui_retro).
|
|
@@ -6,7 +8,7 @@ Retrobot tweets a word that you've tweeted just 1 year ago!
|
|
|
6
8
|
|
|
7
9
|
## Requirements
|
|
8
10
|
|
|
9
|
-
- Ruby
|
|
11
|
+
- Ruby 2.0+
|
|
10
12
|
- Your [tweets.zip](https://blog.twitter.com/2012/your-twitter-archive)
|
|
11
13
|
|
|
12
14
|
## Installation
|
|
@@ -19,7 +21,7 @@ $ cd retrobot
|
|
|
19
21
|
$ bundle install
|
|
20
22
|
```
|
|
21
23
|
|
|
22
|
-
### Using bundler
|
|
24
|
+
### Using bundler
|
|
23
25
|
|
|
24
26
|
This way may be useful for deploying using capistrano or heroku.
|
|
25
27
|
|
|
@@ -63,8 +65,8 @@ $ bin/retrobot -c /path/to/retrobot.yml
|
|
|
63
65
|
or you can run it as a daemon as follows:
|
|
64
66
|
|
|
65
67
|
```
|
|
66
|
-
$ bin/retrobotctl [start|stop]
|
|
68
|
+
$ bin/retrobotctl [start|stop] -- -c /path/to/retrobot.yml
|
|
67
69
|
```
|
|
68
70
|
|
|
69
71
|
## License
|
|
70
|
-
Copyright (c)
|
|
72
|
+
Copyright (c) 2014 Issei Naruta. Retrobot is released under the MIT License.
|
data/lib/retrobot.rb
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
require 'retrobot/version'
|
|
2
2
|
require 'retrobot/config'
|
|
3
|
+
require 'retrobot/tweet'
|
|
4
|
+
require 'retrobot/tweet_filters'
|
|
3
5
|
|
|
6
|
+
require 'active_support'
|
|
4
7
|
require 'active_support/core_ext'
|
|
5
8
|
require 'twitter'
|
|
6
9
|
require 'retryable'
|
|
@@ -15,6 +18,8 @@ class Retrobot
|
|
|
15
18
|
|
|
16
19
|
GEM_ROOT = Pathname.new('..').expand_path(__dir__)
|
|
17
20
|
|
|
21
|
+
attr_reader :config
|
|
22
|
+
|
|
18
23
|
def initialize(argv)
|
|
19
24
|
@argv = argv
|
|
20
25
|
end
|
|
@@ -73,40 +78,31 @@ class Retrobot
|
|
|
73
78
|
end
|
|
74
79
|
|
|
75
80
|
def process_line(line)
|
|
76
|
-
|
|
77
|
-
timestamp, source, text,
|
|
78
|
-
retweeted_status_id, retweeted_status_user_id, retweeted_status_timestamp,
|
|
79
|
-
*expanded_urls = line
|
|
80
|
-
|
|
81
|
-
timestamp = Time.parse(timestamp).localtime
|
|
82
|
-
return false if timestamp > @config.retro_days.ago
|
|
81
|
+
tweet = Tweet.parse_line(line)
|
|
83
82
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
tweet_filters.each do |filter|
|
|
84
|
+
tweet = filter.filter(tweet)
|
|
85
|
+
break unless tweet
|
|
87
86
|
end
|
|
88
87
|
|
|
89
|
-
tweet CGI.unescape_html(text.gsub('@', ''))
|
|
90
88
|
true
|
|
91
89
|
rescue Twitter::Error
|
|
92
90
|
logger.error "#{$!} (#{$!.class})\n #{$@.join("\n ")}"
|
|
93
91
|
true
|
|
92
|
+
rescue Retrobot::TweetFilters::RetryLater
|
|
93
|
+
false
|
|
94
94
|
end
|
|
95
95
|
|
|
96
|
-
def
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
return if @config.dryrun
|
|
107
|
-
retryable(tries: @config.retry_count, sleep: @config.retry_interval) do
|
|
108
|
-
client.update text
|
|
109
|
-
end
|
|
96
|
+
def tweet_filters
|
|
97
|
+
return @tweet_filters if @tweet_filters
|
|
98
|
+
@tweet_filters = []
|
|
99
|
+
@tweet_filters << TweetFilters::RetroDays.new(self)
|
|
100
|
+
@tweet_filters << TweetFilters::AddInReplyToUrl.new(self) if @config.add_in_reply_to_url
|
|
101
|
+
@tweet_filters << TweetFilters::Retweet.new(self)
|
|
102
|
+
@tweet_filters << TweetFilters::RemoveAtmark.new(self)
|
|
103
|
+
@tweet_filters << TweetFilters::Unescape.new(self)
|
|
104
|
+
@tweet_filters << TweetFilters::Tweet.new(self)
|
|
105
|
+
@tweet_filters
|
|
110
106
|
end
|
|
111
107
|
|
|
112
108
|
def init_configuration
|
data/lib/retrobot/config.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require 'active_support'
|
|
1
2
|
require 'active_support/core_ext'
|
|
2
3
|
require 'psych'
|
|
3
4
|
|
|
@@ -10,21 +11,25 @@ class Retrobot
|
|
|
10
11
|
access_token
|
|
11
12
|
access_secret
|
|
12
13
|
retro_days
|
|
14
|
+
retweet
|
|
13
15
|
debug
|
|
14
16
|
dryrun
|
|
15
17
|
loop_interval
|
|
16
18
|
retry_interval
|
|
17
19
|
retry_count
|
|
20
|
+
add_in_reply_to_url
|
|
18
21
|
)
|
|
19
22
|
|
|
20
23
|
DEFAULTS = {
|
|
21
24
|
tweets_csv: './tweets/tweets.csv',
|
|
22
25
|
retro_days: 365,
|
|
26
|
+
retweet: false,
|
|
23
27
|
debug: false,
|
|
24
28
|
dryrun: false,
|
|
25
29
|
loop_interval: 3,
|
|
26
30
|
retry_interval: 3,
|
|
27
|
-
retry_count: 5
|
|
31
|
+
retry_count: 5,
|
|
32
|
+
add_in_reply_to_url: false
|
|
28
33
|
}
|
|
29
34
|
|
|
30
35
|
def initialize(options={})
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'time'
|
|
2
|
+
|
|
3
|
+
class Retrobot
|
|
4
|
+
class Tweet
|
|
5
|
+
attr_accessor :tweet_id, :in_reply_to_status_id, :in_reply_to_user_id, :timestamp, :source, :text,
|
|
6
|
+
:retweeted_status_id, :retweeted_status_user_id, :retweeted_status_timestamp, :expanded_urls
|
|
7
|
+
|
|
8
|
+
def self.parse_line(cols)
|
|
9
|
+
t = self.new
|
|
10
|
+
t.tweet_id = str_to_int_or_nil(cols[0])
|
|
11
|
+
t.in_reply_to_status_id = str_to_int_or_nil(cols[1])
|
|
12
|
+
t.in_reply_to_user_id = str_to_int_or_nil(cols[2])
|
|
13
|
+
t.timestamp = cols[3]
|
|
14
|
+
t.source = cols[4]
|
|
15
|
+
t.text = cols[5]
|
|
16
|
+
t.retweeted_status_id = str_to_int_or_nil(cols[6])
|
|
17
|
+
t.retweeted_status_user_id = str_to_int_or_nil(cols[7])
|
|
18
|
+
t.retweeted_status_timestamp = str_to_time_or_nil(cols[8])
|
|
19
|
+
t.expanded_urls = cols[9..-1]
|
|
20
|
+
t
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.str_to_int_or_nil(str)
|
|
24
|
+
if str.nil? || str.empty?
|
|
25
|
+
nil
|
|
26
|
+
else
|
|
27
|
+
str.to_i
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.str_to_time_or_nil(str)
|
|
32
|
+
if str.nil? || str.empty?
|
|
33
|
+
nil
|
|
34
|
+
else
|
|
35
|
+
Time.parse(str).localtime
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
require 'retrobot/tweet_filters/base'
|
|
2
|
+
require 'retrobot/tweet_filters/remove_atmark'
|
|
3
|
+
require 'retrobot/tweet_filters/retro_days'
|
|
4
|
+
require 'retrobot/tweet_filters/retweet'
|
|
5
|
+
require 'retrobot/tweet_filters/tweet'
|
|
6
|
+
require 'retrobot/tweet_filters/unescape'
|
|
7
|
+
require 'retrobot/tweet_filters/add_in_reply_to_url'
|
|
8
|
+
|
|
9
|
+
class Retrobot
|
|
10
|
+
module TweetFilters
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require 'net/https'
|
|
2
|
+
require 'cgi'
|
|
3
|
+
require 'uri'
|
|
4
|
+
require 'retrobot/tweet_filters/base'
|
|
5
|
+
|
|
6
|
+
class Retrobot
|
|
7
|
+
module TweetFilters
|
|
8
|
+
class AddInReplyToUrl < Base
|
|
9
|
+
TWITTER_BASE_URL = 'https://twitter.com'
|
|
10
|
+
|
|
11
|
+
def initialize(retrobot)
|
|
12
|
+
super
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def filter(tweet)
|
|
16
|
+
if tweet.in_reply_to_status_id
|
|
17
|
+
tweet.text = replace_text(tweet.text, tweet.in_reply_to_status_id)
|
|
18
|
+
tweet
|
|
19
|
+
else
|
|
20
|
+
tweet
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
def http_twitter
|
|
26
|
+
uri = URI.parse(TWITTER_BASE_URL)
|
|
27
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
28
|
+
http.open_timeout = 3
|
|
29
|
+
http.read_timeout = 3
|
|
30
|
+
http.use_ssl = true
|
|
31
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
32
|
+
http
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def replace_text(text, in_reply_to_status_id)
|
|
36
|
+
path_for_redirect = "/%20/status/#{in_reply_to_status_id}"
|
|
37
|
+
|
|
38
|
+
response = begin
|
|
39
|
+
http_twitter.start { |http| http.head(path_for_redirect) }
|
|
40
|
+
rescue IOError, EOFError, Errno::ECONNRESET, Errno::ETIMEDOUT, SystemCallError
|
|
41
|
+
nil
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
in_reply_to_url = if response && !response['location'].blank?
|
|
45
|
+
response['location']
|
|
46
|
+
else
|
|
47
|
+
logger.warn 'could not get in reply to url'
|
|
48
|
+
TWITTER_BASE_URL + path_for_redirect
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
text = text[0..113] + '...' if text.length > 118
|
|
52
|
+
text = text + ' ' + in_reply_to_url
|
|
53
|
+
|
|
54
|
+
text
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
class Retrobot
|
|
2
|
+
module TweetFilters
|
|
3
|
+
class RetryLater < StandardError; end
|
|
4
|
+
|
|
5
|
+
class Base
|
|
6
|
+
def initialize(retrobot)
|
|
7
|
+
@retrobot = retrobot
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def client
|
|
11
|
+
@retrobot.client
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def config
|
|
15
|
+
@retrobot.config
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def logger
|
|
19
|
+
@retrobot.logger
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'active_support'
|
|
2
|
+
require 'active_support/core_ext'
|
|
3
|
+
require 'retrobot/tweet_filters/base'
|
|
4
|
+
|
|
5
|
+
class Retrobot
|
|
6
|
+
module TweetFilters
|
|
7
|
+
class RetroDays < Base
|
|
8
|
+
def initialize(retrobot)
|
|
9
|
+
super
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def filter(tweet)
|
|
13
|
+
if tweet.timestamp > config.retro_days.ago
|
|
14
|
+
raise RetryLater
|
|
15
|
+
else
|
|
16
|
+
tweet
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require 'retryable'
|
|
2
|
+
require 'retrobot/tweet_filters/base'
|
|
3
|
+
|
|
4
|
+
class Retrobot
|
|
5
|
+
module TweetFilters
|
|
6
|
+
class Retweet < Base
|
|
7
|
+
def initialize(retrobot)
|
|
8
|
+
super
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def filter(tweet)
|
|
12
|
+
if tweet.retweeted_status_id
|
|
13
|
+
if config.retweet
|
|
14
|
+
retweet tweet.retweeted_status_id, tweet.text
|
|
15
|
+
else
|
|
16
|
+
logger.info "retweet (skipped): #{tweet.retweeted_status_id} \"#{tweet.text}\""
|
|
17
|
+
end
|
|
18
|
+
return nil
|
|
19
|
+
else
|
|
20
|
+
tweet
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
def retweet(status_id, text=nil)
|
|
26
|
+
logger.info "retweet: #{status_id} \"#{text}\""
|
|
27
|
+
return if config.dryrun
|
|
28
|
+
retryable(tries: config.retry_count, sleep: config.retry_interval) do
|
|
29
|
+
client.retweet status_id
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'retrobot/tweet_filters/base'
|
|
2
|
+
require 'retryable'
|
|
3
|
+
|
|
4
|
+
class Retrobot
|
|
5
|
+
module TweetFilters
|
|
6
|
+
class Tweet < Base
|
|
7
|
+
def initialize(retrobot)
|
|
8
|
+
super
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def filter(tweet)
|
|
12
|
+
tweet tweet.text
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
def tweet(text)
|
|
17
|
+
logger.info "tweet: #{text}"
|
|
18
|
+
return if config.dryrun
|
|
19
|
+
retryable(tries: config.retry_count, sleep: config.retry_interval) do
|
|
20
|
+
client.update text
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/retrobot/version.rb
CHANGED
data/retrobot.example.yml
CHANGED
|
@@ -4,5 +4,7 @@ consumer_secret: your_consumer_secret
|
|
|
4
4
|
access_token: your_access_token
|
|
5
5
|
access_secret: your_access_secret
|
|
6
6
|
# retro_days: 365 (default=365 / how days long ago do you want to see? / in N days ago)
|
|
7
|
+
# retweet: false (default)
|
|
7
8
|
# debug: false (default)
|
|
8
9
|
# dryrun: false (default)
|
|
10
|
+
# add_in_reply_to_url: false (default=false / add url of in_reply_to into the tweet)
|
data/retrobot.gemspec
CHANGED
|
@@ -22,5 +22,8 @@ Gem::Specification.new do |gem|
|
|
|
22
22
|
gem.add_dependency 'retryable'
|
|
23
23
|
gem.add_dependency 'daemons'
|
|
24
24
|
|
|
25
|
+
gem.add_development_dependency 'rspec', '= 2.99'
|
|
26
|
+
gem.add_development_dependency 'timecop'
|
|
27
|
+
|
|
25
28
|
gem.add_runtime_dependency 'get-twitter-oauth-token'
|
|
26
29
|
end
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
require 'retrobot/tweet'
|
|
2
|
+
require 'retrobot/tweet_filters'
|
|
3
|
+
require 'retrobot/config'
|
|
4
|
+
require 'logger'
|
|
5
|
+
require 'timecop'
|
|
6
|
+
|
|
7
|
+
describe Retrobot::TweetFilters do
|
|
8
|
+
let(:retrobot) {
|
|
9
|
+
double(:retrobot,
|
|
10
|
+
logger: Logger.new('/dev/null'),
|
|
11
|
+
config: config,
|
|
12
|
+
client: client
|
|
13
|
+
)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let(:client) { double('client', retweet: nil, update: nil) }
|
|
17
|
+
let(:filter) { filter_class.new retrobot }
|
|
18
|
+
let(:config) do
|
|
19
|
+
Retrobot::Config.new
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe 'AddInReplyToUrl#filter' do
|
|
23
|
+
let(:filter_class) { Retrobot::TweetFilters::AddInReplyToUrl }
|
|
24
|
+
|
|
25
|
+
it 'adds in_reply_to_url' do
|
|
26
|
+
# https://twitter.com/mirakui/status/419483601634205696
|
|
27
|
+
tweet_before = Retrobot::Tweet.new.tap do |t|
|
|
28
|
+
t.in_reply_to_status_id = 419483520973565952
|
|
29
|
+
t.text = '@mirakui_retro おめでとうございます'
|
|
30
|
+
end
|
|
31
|
+
tweet_after = filter.filter tweet_before
|
|
32
|
+
expect(tweet_after.text).to eq('@mirakui_retro おめでとうございます https://twitter.com/mirakui_retro/status/419483520973565952')
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe 'RetroDays' do
|
|
37
|
+
let(:filter_class) { Retrobot::TweetFilters::RetroDays }
|
|
38
|
+
let(:now) { Time.new(2014,01,01).localtime }
|
|
39
|
+
let(:config) do
|
|
40
|
+
Retrobot::Config.new retro_days: 365
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'retrys if newer than retro_days' do
|
|
44
|
+
Timecop.freeze(now) do
|
|
45
|
+
tweet_before = Retrobot::Tweet.new.tap do |t|
|
|
46
|
+
t.timestamp = now - 364.days
|
|
47
|
+
end
|
|
48
|
+
expect{ filter.filter(tweet_before) }.to raise_error(Retrobot::TweetFilters::RetryLater)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'tweets tweet older than retro_days' do
|
|
53
|
+
Timecop.freeze(now) do
|
|
54
|
+
tweet_before = Retrobot::Tweet.new.tap do |t|
|
|
55
|
+
t.timestamp = now - 365.days
|
|
56
|
+
end
|
|
57
|
+
expect(filter.filter(tweet_before)).to eq(tweet_before)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
describe 'RemoveAtmark' do
|
|
63
|
+
let(:filter_class) { Retrobot::TweetFilters::RemoveAtmark }
|
|
64
|
+
|
|
65
|
+
it 'removes atmark' do
|
|
66
|
+
tweet_before = Retrobot::Tweet.new.tap do |t|
|
|
67
|
+
t.text = '@mirakui_retro hello'
|
|
68
|
+
end
|
|
69
|
+
tweet_after = filter.filter(tweet_before)
|
|
70
|
+
expect(tweet_after.text).to eq('mirakui_retro hello')
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
describe 'Unescape' do
|
|
75
|
+
let(:filter_class) { Retrobot::TweetFilters::Unescape }
|
|
76
|
+
|
|
77
|
+
it 'unescapes text' do
|
|
78
|
+
tweet_before = Retrobot::Tweet.new.tap do |t|
|
|
79
|
+
t.text = '>_<'
|
|
80
|
+
end
|
|
81
|
+
tweet_after = filter.filter(tweet_before)
|
|
82
|
+
expect(tweet_after.text).to eq('>_<')
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
describe 'Retweet' do
|
|
87
|
+
let(:filter_class) { Retrobot::TweetFilters::Retweet }
|
|
88
|
+
|
|
89
|
+
context 'retweeted_status_id is present' do
|
|
90
|
+
let(:tweet_before) do
|
|
91
|
+
Retrobot::Tweet.new.tap do |t|
|
|
92
|
+
t.retweeted_status_id = 123456
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
context 'config.retweet is true' do
|
|
97
|
+
let(:config) { Retrobot::Config.new retweet: true }
|
|
98
|
+
|
|
99
|
+
it 'retweets' do
|
|
100
|
+
tweet_after = filter.filter(tweet_before)
|
|
101
|
+
expect(tweet_after).to be(nil)
|
|
102
|
+
expect(retrobot.client).to have_received(:retweet).with(123456)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
context 'config.retweet is false' do
|
|
107
|
+
let(:config) { Retrobot::Config.new retweet: false }
|
|
108
|
+
|
|
109
|
+
it 'does not retweet' do
|
|
110
|
+
tweet_after = filter.filter(tweet_before)
|
|
111
|
+
expect(tweet_after).to be(nil)
|
|
112
|
+
expect(retrobot.client).not_to have_received(:retweet)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
context 'retweeted_status_id is blank' do
|
|
118
|
+
let(:tweet_before) do
|
|
119
|
+
Retrobot::Tweet.new.tap do |t|
|
|
120
|
+
t.retweeted_status_id = nil
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
let(:config) { Retrobot::Config.new retweet: true }
|
|
124
|
+
|
|
125
|
+
it 'does not retweet' do
|
|
126
|
+
tweet_after = filter.filter(tweet_before)
|
|
127
|
+
expect(tweet_after).to eq(tweet_before)
|
|
128
|
+
expect(retrobot.client).not_to have_received(:retweet)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
describe 'Tweet' do
|
|
134
|
+
let(:filter_class) { Retrobot::TweetFilters::Tweet }
|
|
135
|
+
|
|
136
|
+
it 'tweets text' do
|
|
137
|
+
tweet_before = Retrobot::Tweet.new.tap do |t|
|
|
138
|
+
t.text = 'hello'
|
|
139
|
+
end
|
|
140
|
+
tweet_after = filter.filter(tweet_before)
|
|
141
|
+
expect(tweet_after).to be(nil)
|
|
142
|
+
expect(retrobot.client).to have_received(:update).with('hello')
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
require 'timecop'
|
|
4
|
+
require 'logger'
|
|
5
|
+
require 'retrobot'
|
|
6
|
+
require 'retrobot/config'
|
|
7
|
+
|
|
8
|
+
describe Retrobot do
|
|
9
|
+
let(:retrobot) do
|
|
10
|
+
Retrobot.new(nil).tap do |r|
|
|
11
|
+
r.instance_variable_set('@config', config)
|
|
12
|
+
r.instance_variable_set('@logger', Logger.new('/dev/null'))
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
let(:config) do
|
|
17
|
+
Retrobot::Config.new(
|
|
18
|
+
retro_days: 365,
|
|
19
|
+
retweet: retweet
|
|
20
|
+
)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
let(:client) { retrobot.client }
|
|
24
|
+
let(:retweet) { false }
|
|
25
|
+
|
|
26
|
+
describe '#process_line' do
|
|
27
|
+
let(:line) do
|
|
28
|
+
# tweet_id, in_reply_to_status_id, in_reply_to_user_id, timestamp, source,
|
|
29
|
+
# text, retweeted_status_id, retweeted_status_user_id, retweeted_status_timestamp,
|
|
30
|
+
['449471248742236160', '', '', '2014-03-28 09:01:11 +0000', '<a href="http://ifttt.com" rel="nofollow">IFTTT</a>',
|
|
31
|
+
text, retweeted_status_id, '', '', 'http://ift.tt/1d1CL0W']
|
|
32
|
+
end
|
|
33
|
+
let(:text) { '花金だーワッショーイ!テンションAGEAGEマック http://t.co/nvXD6e2rdG' }
|
|
34
|
+
let(:retweeted_status_id) { '' }
|
|
35
|
+
|
|
36
|
+
context '365 days passed from the day' do
|
|
37
|
+
around do |example|
|
|
38
|
+
Timecop.freeze('2015-03-28 09:01:11 +0000') do
|
|
39
|
+
example.run
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'should tweet' do
|
|
44
|
+
expect(client).to receive(:update).with('花金だーワッショーイ!テンションAGEAGEマック http://t.co/nvXD6e2rdG')
|
|
45
|
+
expect(retrobot.process_line line).to be true
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
context 'with a text includes mention' do
|
|
49
|
+
let(:text) { '@mirakui hello' }
|
|
50
|
+
|
|
51
|
+
it '"@" should be removed' do
|
|
52
|
+
expect(client).to receive(:update).with('mirakui hello')
|
|
53
|
+
expect(retrobot.process_line line).to be true
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
context 'with a line has retweeted_status_id' do
|
|
58
|
+
let(:text) { 'RT @mirakui hello' }
|
|
59
|
+
let(:retweeted_status_id) { '123456789' }
|
|
60
|
+
|
|
61
|
+
context 'if retweeting enabled' do
|
|
62
|
+
let(:retweet) { true }
|
|
63
|
+
|
|
64
|
+
it 'should be retweeted' do
|
|
65
|
+
expect(client).to receive(:retweet).with(123456789)
|
|
66
|
+
expect(client).not_to receive(:update)
|
|
67
|
+
expect(retrobot.process_line line).to be true
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
context 'if retweeting disabled' do
|
|
72
|
+
let(:retweet) { false }
|
|
73
|
+
|
|
74
|
+
it 'should not be retweeted' do
|
|
75
|
+
expect(client).not_to receive(:retweet)
|
|
76
|
+
expect(client).not_to receive(:update)
|
|
77
|
+
expect(retrobot.process_line line).to be true
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
context "365 days have not passed from the day" do
|
|
84
|
+
it 'should not tweet' do
|
|
85
|
+
Timecop.freeze('2015-03-28 09:01:10 +0000') do
|
|
86
|
+
expect(client).not_to receive(:update)
|
|
87
|
+
expect(retrobot.process_line line).to be false
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
|
4
|
+
# loaded once.
|
|
5
|
+
#
|
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
|
7
|
+
RSpec.configure do |config|
|
|
8
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
|
9
|
+
config.run_all_when_everything_filtered = true
|
|
10
|
+
config.filter_run :focus
|
|
11
|
+
|
|
12
|
+
# Run specs in random order to surface order dependencies. If you find an
|
|
13
|
+
# order dependency and want to debug it, you can fix the order by providing
|
|
14
|
+
# the seed, which is printed after each run.
|
|
15
|
+
# --seed 1234
|
|
16
|
+
config.order = 'random'
|
|
17
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: retrobot
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Issei Naruta
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2014-
|
|
11
|
+
date: 2014-06-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: twitter
|
|
@@ -66,6 +66,34 @@ dependencies:
|
|
|
66
66
|
- - ">="
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
68
|
version: '0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: rspec
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - '='
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '2.99'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - '='
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '2.99'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: timecop
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0'
|
|
69
97
|
- !ruby/object:Gem::Dependency
|
|
70
98
|
name: get-twitter-oauth-token
|
|
71
99
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -91,6 +119,8 @@ extensions: []
|
|
|
91
119
|
extra_rdoc_files: []
|
|
92
120
|
files:
|
|
93
121
|
- ".gitignore"
|
|
122
|
+
- ".rspec"
|
|
123
|
+
- ".travis.yml"
|
|
94
124
|
- ChangeLog.md
|
|
95
125
|
- Gemfile
|
|
96
126
|
- Gemfile.lock
|
|
@@ -101,10 +131,22 @@ files:
|
|
|
101
131
|
- bin/retrobotctl
|
|
102
132
|
- lib/retrobot.rb
|
|
103
133
|
- lib/retrobot/config.rb
|
|
134
|
+
- lib/retrobot/tweet.rb
|
|
135
|
+
- lib/retrobot/tweet_filters.rb
|
|
136
|
+
- lib/retrobot/tweet_filters/add_in_reply_to_url.rb
|
|
137
|
+
- lib/retrobot/tweet_filters/base.rb
|
|
138
|
+
- lib/retrobot/tweet_filters/remove_atmark.rb
|
|
139
|
+
- lib/retrobot/tweet_filters/retro_days.rb
|
|
140
|
+
- lib/retrobot/tweet_filters/retweet.rb
|
|
141
|
+
- lib/retrobot/tweet_filters/tweet.rb
|
|
142
|
+
- lib/retrobot/tweet_filters/unescape.rb
|
|
104
143
|
- lib/retrobot/version.rb
|
|
105
144
|
- log/.keep
|
|
106
145
|
- retrobot.example.yml
|
|
107
146
|
- retrobot.gemspec
|
|
147
|
+
- spec/lib/retrobot/tweet_filters_spec.rb
|
|
148
|
+
- spec/lib/retrobot_spec.rb
|
|
149
|
+
- spec/spec_helper.rb
|
|
108
150
|
- tmp/.keep
|
|
109
151
|
homepage: https://github.com/mirakui/retrobot
|
|
110
152
|
licenses: []
|
|
@@ -129,4 +171,7 @@ rubygems_version: 2.2.2
|
|
|
129
171
|
signing_key:
|
|
130
172
|
specification_version: 4
|
|
131
173
|
summary: 'Retrobot tweets a word that you''ve tweeted just 1 year ago. (example: @mirakui_retro)'
|
|
132
|
-
test_files:
|
|
174
|
+
test_files:
|
|
175
|
+
- spec/lib/retrobot/tweet_filters_spec.rb
|
|
176
|
+
- spec/lib/retrobot_spec.rb
|
|
177
|
+
- spec/spec_helper.rb
|