twitter_friendly 1.2.0 → 1.2.1
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/.gitignore +2 -2
- data/Gemfile.lock +1 -1
- data/README.md +10 -9
- data/lib/twitter_friendly/cache.rb +15 -17
- data/lib/twitter_friendly/caching_and_logging.rb +6 -6
- data/lib/twitter_friendly/client.rb +5 -3
- data/lib/twitter_friendly/log_subscriber.rb +24 -11
- data/lib/twitter_friendly/logger.rb +1 -1
- data/lib/twitter_friendly/rest/users.rb +4 -4
- data/lib/twitter_friendly/serializer.rb +8 -8
- data/lib/twitter_friendly/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 810019b532f5f365b544ca6e0a0066717794b8975b59ae0a840b74f44377bff6
|
4
|
+
data.tar.gz: 75f3b7052fa926da7457b53f71d0f2f6e08496efd02042750681678b53d351dd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '08a9a4ef337d993f1cb3bb6689df73d67b5adc74576214206774c5dc2b720e0ef66c30a376c2d122c4a70d7dc85661f6114508ad0e030819f52a0c65370a3033'
|
7
|
+
data.tar.gz: f26d6b48033db9dc96752a55c12a5e7ffe1c3610773f0014af8d1a69b4c84384de5eec858c204634212c1e205b2579ec6cf689a8dd0cdf634031a65510520ca4
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -5,16 +5,16 @@
|
|
5
5
|
|
6
6
|
The twitter_friendly is a gem to crawl many friends/followers with minimal code. When you want to get a list of friends/followers for a user, all you need to write is the below.
|
7
7
|
|
8
|
-
```
|
8
|
+
```ruby
|
9
9
|
require 'twitter_friendly'
|
10
10
|
|
11
11
|
client =
|
12
12
|
TwitterFriendly::Client.new(
|
13
|
-
consumer_key:
|
14
|
-
consumer_secret:
|
15
|
-
access_token:
|
13
|
+
consumer_key: 'CONSUMER_KEY',
|
14
|
+
consumer_secret: 'CONSUMER_SECRET',
|
15
|
+
access_token: 'ACCESS_TOKEN',
|
16
16
|
access_token_secret: 'ACCESS_TOKEN_SECRET',
|
17
|
-
expires_in:
|
17
|
+
expires_in: 86400 # 1day
|
18
18
|
)
|
19
19
|
|
20
20
|
ids = []
|
@@ -22,7 +22,8 @@ ids = []
|
|
22
22
|
begin
|
23
23
|
ids = client.follower_ids('yousuck2020')
|
24
24
|
rescue Twitter::Error::TooManyRequests => e
|
25
|
-
|
25
|
+
seconds = e.rate_limit.reset_in.to_i # or client.rate_limit.follower_ids[:reset_in]
|
26
|
+
sleep seconds
|
26
27
|
retry
|
27
28
|
end
|
28
29
|
|
@@ -44,13 +45,13 @@ gem 'twitter_friendly'
|
|
44
45
|
|
45
46
|
And then execute:
|
46
47
|
|
47
|
-
```
|
48
|
+
```bash
|
48
49
|
$ bundle
|
49
50
|
```
|
50
51
|
|
51
52
|
Or install it yourself as:
|
52
53
|
|
53
|
-
```
|
54
|
+
```bash
|
54
55
|
$ gem install twitter_friendly
|
55
56
|
```
|
56
57
|
|
@@ -58,7 +59,7 @@ $ gem install twitter_friendly
|
|
58
59
|
|
59
60
|
You can pass configuration options as a block to `TwitterFriendly::Client.new` just like the below.
|
60
61
|
|
61
|
-
```
|
62
|
+
```ruby
|
62
63
|
client = TwitterFriendly::Client.new do |config|
|
63
64
|
config.consumer_key = "YOUR_CONSUMER_KEY"
|
64
65
|
config.consumer_secret = "YOUR_CONSUMER_SECRET"
|
@@ -9,37 +9,35 @@ module TwitterFriendly
|
|
9
9
|
def initialize(*args)
|
10
10
|
options = {expires_in: 1.hour, race_condition_ttl: 5.minutes}.merge(args.extract_options!)
|
11
11
|
|
12
|
-
path = options[:cache_dir] || File.join('
|
12
|
+
path = options[:cache_dir] || File.join('cache')
|
13
13
|
FileUtils.mkdir_p(path) unless File.exists?(path)
|
14
14
|
@client = ::ActiveSupport::Cache::FileStore.new(path, options)
|
15
15
|
end
|
16
16
|
|
17
|
-
|
18
|
-
#
|
19
|
-
# @option serialize_options [Array] :args
|
20
|
-
def fetch(key, serialize_options, &block)
|
17
|
+
def fetch(key, args:, &block)
|
21
18
|
block_result = nil
|
22
|
-
yield_and_encode =
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
19
|
+
yield_and_encode = Proc.new do
|
20
|
+
block_result = yield
|
21
|
+
encode(block_result, args: args)
|
22
|
+
end
|
23
|
+
|
24
|
+
# 目的のデータがキャッシュになかった場合、キャッシュにはシリアライズしたJSONを保存しつつ、
|
25
|
+
# このメソッドの呼び出し元にはJSONにシリアライズする前の結果を返している。
|
26
|
+
# こうしないと、不要なデコードをすることになってしまう。
|
27
27
|
|
28
28
|
fetch_result = @client.fetch(key, &yield_and_encode)
|
29
29
|
|
30
|
-
block_result || decode(fetch_result,
|
30
|
+
block_result || decode(fetch_result, args: args)
|
31
31
|
end
|
32
32
|
|
33
33
|
private
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
Serializer.encode(obj, options)
|
35
|
+
def encode(obj, args:)
|
36
|
+
Serializer.encode(obj, args: args)
|
38
37
|
end
|
39
38
|
|
40
|
-
|
41
|
-
|
42
|
-
Serializer.decode(str, options)
|
39
|
+
def decode(str, args:)
|
40
|
+
Serializer.decode(str, args: args)
|
43
41
|
end
|
44
42
|
end
|
45
43
|
end
|
@@ -39,18 +39,18 @@ module TwitterFriendly
|
|
39
39
|
|
40
40
|
module_function
|
41
41
|
|
42
|
-
def start_processing(
|
43
|
-
payload = {operation:
|
42
|
+
def start_processing(method_name, options)
|
43
|
+
payload = {operation: method_name}.merge(options)
|
44
44
|
::ActiveSupport::Notifications.instrument('start_processing.twitter_friendly', payload) {}
|
45
45
|
end
|
46
46
|
|
47
|
-
def complete_processing(
|
48
|
-
payload = {operation:
|
47
|
+
def complete_processing(method_name, options)
|
48
|
+
payload = {operation: method_name}.merge(options)
|
49
49
|
::ActiveSupport::Notifications.instrument('complete_processing.twitter_friendly', payload) { yield(payload) }
|
50
50
|
end
|
51
51
|
|
52
|
-
def perform_request(
|
53
|
-
payload = {operation: 'request', args: [
|
52
|
+
def perform_request(method_name, options, &block)
|
53
|
+
payload = {operation: 'request', args: [method_name, options]}
|
54
54
|
::ActiveSupport::Notifications.instrument('request.twitter_friendly', payload) { yield(payload) }
|
55
55
|
end
|
56
56
|
end
|
@@ -26,12 +26,14 @@ module TwitterFriendly
|
|
26
26
|
|
27
27
|
def initialize(*args)
|
28
28
|
options = args.extract_options!
|
29
|
-
@twitter = Twitter::REST::Client.new(options.slice(:access_token, :access_token_secret, :consumer_key, :consumer_secret))
|
30
29
|
|
30
|
+
@twitter = Twitter::REST::Client.new(options.slice(:access_token, :access_token_secret, :consumer_key, :consumer_secret))
|
31
31
|
options.except!(:access_token, :access_token_secret, :consumer_key, :consumer_secret)
|
32
|
-
@cache = TwitterFriendly::Cache.new(options)
|
33
32
|
|
34
|
-
@
|
33
|
+
@cache = TwitterFriendly::Cache.new(options.slice(:cache_dir, :expires_in, :race_condition_ttl))
|
34
|
+
options.except!(:cache_dir, :expires_in, :race_condition_ttl)
|
35
|
+
|
36
|
+
@logger = TwitterFriendly::Logger.new(options.slice(:log_dir, :log_level))
|
35
37
|
|
36
38
|
unless subscriber_attached?
|
37
39
|
if @logger.level == ::Logger::DEBUG
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module TwitterFriendly
|
2
2
|
module Logging
|
3
3
|
def truncated_payload(payload)
|
4
|
+
return '' if payload.empty?
|
4
5
|
return payload.inspect if !payload.has_key?(:args) || !payload[:args].is_a?(Array) || payload[:args].empty? || !payload[:args][0].is_a?(Array)
|
5
6
|
|
6
7
|
args = payload[:args].dup
|
@@ -30,24 +31,28 @@ module TwitterFriendly
|
|
30
31
|
include Logging
|
31
32
|
|
32
33
|
def start_processing(event)
|
33
|
-
|
34
|
+
info do
|
34
35
|
payload = event.payload
|
35
|
-
|
36
|
+
operation = payload.delete(:operation)
|
36
37
|
|
37
38
|
if payload[:super_operation]
|
38
|
-
"#{
|
39
|
+
"TF::Started #{operation} in #{payload[:super_operation][0]} at #{Time.now}"
|
39
40
|
else
|
40
|
-
"#{
|
41
|
+
"TF::Started #{operation} at #{Time.now}"
|
41
42
|
end
|
42
43
|
end
|
43
44
|
end
|
44
45
|
|
45
46
|
def complete_processing(event)
|
46
|
-
|
47
|
+
info do
|
47
48
|
payload = event.payload
|
48
|
-
|
49
|
+
operation = payload.delete(:operation)
|
49
50
|
|
50
|
-
|
51
|
+
if payload.empty?
|
52
|
+
"TF::Completed #{operation} in #{event.duration.round(1)}ms"
|
53
|
+
else
|
54
|
+
"TF::Completed #{operation} in #{event.duration.round(1)}ms #{truncated_payload(payload)}"
|
55
|
+
end
|
51
56
|
end
|
52
57
|
end
|
53
58
|
|
@@ -66,11 +71,19 @@ module TwitterFriendly
|
|
66
71
|
debug do
|
67
72
|
payload = event.payload
|
68
73
|
payload.delete(:name)
|
69
|
-
operation = payload.delete(:operation)
|
70
|
-
|
71
|
-
|
74
|
+
operation = payload.delete(:operation).capitalize
|
75
|
+
args = payload[:args]
|
76
|
+
method_name = args.shift
|
77
|
+
|
78
|
+
name = " TW::#{operation} #{method_name} (#{event.duration.round(1)}ms)"
|
79
|
+
c = (%i(Encode Decode).include?(operation.to_sym)) ? YELLOW : CYAN
|
72
80
|
name = color(name, c, true)
|
73
|
-
|
81
|
+
|
82
|
+
if args.size == 1 && args[0].is_a?(Hash) && args[0].empty?
|
83
|
+
" #{name}"
|
84
|
+
else
|
85
|
+
" #{name} #{args[1]}"
|
86
|
+
end
|
74
87
|
end
|
75
88
|
end
|
76
89
|
|
@@ -8,7 +8,7 @@ module TwitterFriendly
|
|
8
8
|
def_delegators :@logger, :debug, :info, :warn, :error, :fatal, :level
|
9
9
|
|
10
10
|
def initialize(options = {})
|
11
|
-
path = options[:log_dir] || File.join('
|
11
|
+
path = options[:log_dir] || File.join('log')
|
12
12
|
FileUtils.mkdir_p(path) unless File.exists?(path)
|
13
13
|
|
14
14
|
@logger = ::Logger.new(File.join(path, 'twitter_friendly.log'))
|
@@ -3,8 +3,8 @@ require 'parallel'
|
|
3
3
|
module TwitterFriendly
|
4
4
|
module REST
|
5
5
|
module Users
|
6
|
-
def verify_credentials(
|
7
|
-
@twitter.verify_credentials(
|
6
|
+
def verify_credentials(include_entities: false, skip_status: true, include_email: true)
|
7
|
+
@twitter.verify_credentials(include_entities: include_entities, skip_status: skip_status, include_email: include_email)&.to_hash
|
8
8
|
end
|
9
9
|
|
10
10
|
def user?(*args)
|
@@ -19,9 +19,9 @@ module TwitterFriendly
|
|
19
19
|
|
20
20
|
def users(values, options = {})
|
21
21
|
if values.size <= MAX_USERS_PER_REQUEST
|
22
|
-
@twitter.users(values, options)
|
22
|
+
@twitter.users(values, options).map(&:to_h)
|
23
23
|
else
|
24
|
-
parallel(in_threads:
|
24
|
+
parallel(in_threads: 6) do |batch|
|
25
25
|
values.each_slice(MAX_USERS_PER_REQUEST) { |targets| batch.users(targets, options) }
|
26
26
|
end.flatten
|
27
27
|
end
|
@@ -4,14 +4,14 @@ require 'oj'
|
|
4
4
|
module TwitterFriendly
|
5
5
|
class Serializer
|
6
6
|
class << self
|
7
|
-
def encode(obj,
|
8
|
-
Instrumenter.perform_encode(
|
7
|
+
def encode(obj, args:)
|
8
|
+
Instrumenter.perform_encode(args: args) do
|
9
9
|
(!!obj == obj) ? obj : coder.encode(obj)
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
-
def decode(str,
|
14
|
-
Instrumenter.perform_decode(
|
13
|
+
def decode(str, args:)
|
14
|
+
Instrumenter.perform_decode(args: args) do
|
15
15
|
str.kind_of?(String) ? coder.decode(str) : str
|
16
16
|
end
|
17
17
|
end
|
@@ -31,13 +31,13 @@ module TwitterFriendly
|
|
31
31
|
|
32
32
|
module_function
|
33
33
|
|
34
|
-
def perform_encode(
|
35
|
-
payload = {operation: 'encode', args:
|
34
|
+
def perform_encode(args:, &block)
|
35
|
+
payload = {operation: 'encode', args: args}
|
36
36
|
::ActiveSupport::Notifications.instrument('encode.twitter_friendly', payload) { yield(payload) }
|
37
37
|
end
|
38
38
|
|
39
|
-
def perform_decode(
|
40
|
-
payload = {operation: 'decode', args:
|
39
|
+
def perform_decode(args:, &block)
|
40
|
+
payload = {operation: 'decode', args: args}
|
41
41
|
::ActiveSupport::Notifications.instrument('decode.twitter_friendly', payload) { yield(payload) }
|
42
42
|
end
|
43
43
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: twitter_friendly
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ts-3156
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-04-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|