reddit_api 0.1.18 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/reddit_api/client.rb +27 -85
- data/lib/reddit_api/comments.rb +18 -8
- data/lib/reddit_api/posts.rb +11 -2
- data/lib/reddit_api/query.rb +56 -0
- data/lib/reddit_api/requestor.rb +16 -28
- data/lib/reddit_api/response_parser.rb +48 -0
- data/lib/reddit_api/subreddits.rb +23 -7
- data/lib/reddit_api/version.rb +1 -1
- data/lib/reddit_api.rb +2 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e2c1a49844a77703602af21827434a0d54f4db28
|
4
|
+
data.tar.gz: d59933c5bbeb7b06c38bf1319c99ed6e343317e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a631d30ae80980cab7ba975181c0e015da0abe7a98004f317f435fc99c92630c9cb93cddb063899f291cc4cd18b78cf032e64826c3f19a5506b9b012a1738d1
|
7
|
+
data.tar.gz: 7ff3eda53055f62798f0344de7debca41da2e541806248d007ae0e9450f8a2ce0434c8872b5956909215ae0f186b132dc2c40c7634b193dab9982578ebc6c59e
|
data/lib/reddit_api/client.rb
CHANGED
@@ -11,117 +11,59 @@ module RedditApi
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
attr_reader :agent, :id, :password, :secret, :username, :failures
|
15
|
-
|
16
|
-
MAX_FAILURES = 5
|
17
|
-
ERROR_CODES = (400..511)
|
18
14
|
SLEEP_TIME = self.sleep_time
|
15
|
+
MAX_FAILURES = 5
|
16
|
+
|
17
|
+
attr_reader :failures
|
19
18
|
|
20
19
|
def initialize(args = {})
|
21
20
|
@client = args.fetch(:client, HTTParty)
|
22
21
|
@requestor = args.fetch(:requestor, RedditApi::Requestor.new(client: client))
|
23
|
-
@
|
22
|
+
@parser = args.fetch(:parser, RedditApi::ResponseParser)
|
24
23
|
@null_response_factory = RedditApi:: NullResponse
|
25
|
-
@
|
24
|
+
@failures = args.fetch(:failures, 0)
|
26
25
|
end
|
27
26
|
|
28
|
-
def get(
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
27
|
+
def get(query)
|
28
|
+
while query.capture_count < query.count && failures < MAX_FAILURES
|
29
|
+
response = send_request(query)
|
30
|
+
response = parser.parse_response(response, query.count)
|
31
|
+
update_progress(query, response)
|
33
32
|
end
|
33
|
+
reset_failures
|
34
34
|
end
|
35
35
|
|
36
36
|
protected
|
37
|
-
attr_writer :failures
|
37
|
+
attr_writer :failures
|
38
38
|
private
|
39
|
-
attr_reader :client, :
|
40
|
-
:requestor
|
39
|
+
attr_reader :client, :null_response_factory, :requestor, :parser
|
41
40
|
|
42
|
-
def
|
41
|
+
def send_request(query)
|
43
42
|
sleep(SLEEP_TIME)
|
44
|
-
|
45
|
-
self.last_record = offset
|
46
|
-
while !break_get?(records, count)
|
47
|
-
new_records = request_records(endpoint, count, resource_type)
|
48
|
-
collect_records(new_records, records, count)
|
49
|
-
end
|
50
|
-
after_collection
|
51
|
-
records.keys
|
52
|
-
end
|
53
|
-
|
54
|
-
def get_one(endpoint, count, resource_type)
|
55
|
-
request_records(endpoint, count, resource_type)
|
56
|
-
end
|
57
|
-
|
58
|
-
def request_records(endpoint, count, resource_type)
|
59
|
-
response = send_request(endpoint, resource_type)
|
60
|
-
parse_response(response, count)
|
61
|
-
end
|
62
|
-
|
63
|
-
def collect_records(new_records, collected_records, count)
|
64
|
-
new_records.each do |record|
|
65
|
-
collected_records[record] = true
|
66
|
-
break if collected_records.length == count
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def after_collection
|
71
|
-
self.last_record = nil
|
72
|
-
self.failures = 0
|
73
|
-
end
|
74
|
-
|
75
|
-
def send_request(endpoint, resource_type)
|
76
|
-
request = requestor.build(endpoint, resource_type, last_record)
|
43
|
+
request = requestor.build(query)
|
77
44
|
response = client.get(*request)
|
78
45
|
response || null_response_factory.new
|
79
46
|
end
|
80
47
|
|
81
|
-
def
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
end
|
48
|
+
def update_progress(query, response)
|
49
|
+
captured_before = query.capture_count
|
50
|
+
update_query(query, response)
|
51
|
+
captured_after = query.capture_count
|
52
|
+
update_failures(captured_before, captured_after, query.count)
|
87
53
|
end
|
88
54
|
|
89
|
-
def
|
90
|
-
|
55
|
+
def update_query(query, response)
|
56
|
+
query.add_records(response)
|
91
57
|
end
|
92
58
|
|
93
|
-
def
|
94
|
-
|
95
|
-
|
96
|
-
[]
|
97
|
-
else
|
98
|
-
nil
|
59
|
+
def update_failures(captured_before, captured_after, count)
|
60
|
+
if captured_before >= captured_after
|
61
|
+
self.failures += 1
|
99
62
|
end
|
100
63
|
end
|
101
64
|
|
102
|
-
def
|
103
|
-
|
104
|
-
handle_plural_response(response)
|
105
|
-
else
|
106
|
-
response
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
def handle_plural_response(response)
|
111
|
-
if records = response["data"]["children"]
|
112
|
-
store_last_record(records)
|
113
|
-
else
|
114
|
-
handle_bad_response
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def store_last_record(records)
|
119
|
-
self.last_record = records[-1]
|
120
|
-
records
|
121
|
-
end
|
122
|
-
|
123
|
-
def break_get?(records, desired_count)
|
124
|
-
records.length >= desired_count || failures >= MAX_FAILURES
|
65
|
+
def reset_failures
|
66
|
+
self.failures = 0
|
125
67
|
end
|
126
68
|
|
127
69
|
end
|
data/lib/reddit_api/comments.rb
CHANGED
@@ -7,6 +7,7 @@ module RedditApi
|
|
7
7
|
def initialize(args = {})
|
8
8
|
@client = args.fetch(:client, RedditApi::Client.new)
|
9
9
|
@comment_factory = RedditApi::Comment
|
10
|
+
@query_factory = RedditApi::Query
|
10
11
|
@offset = nil
|
11
12
|
@failures = 0
|
12
13
|
end
|
@@ -26,7 +27,7 @@ module RedditApi
|
|
26
27
|
subreddits.keys
|
27
28
|
end
|
28
29
|
|
29
|
-
def most_recent_comments(user, count
|
30
|
+
def most_recent_comments(user, count, offset = nil)
|
30
31
|
comments_data = most_recent_comment_data(user.username, count, offset)
|
31
32
|
build_all_comments(comments_data)
|
32
33
|
end
|
@@ -35,7 +36,22 @@ module RedditApi
|
|
35
36
|
attr_accessor :failures
|
36
37
|
attr_writer :offset, :failures
|
37
38
|
private
|
38
|
-
attr_reader :client, :comment_factory, :offset
|
39
|
+
attr_reader :client, :comment_factory, :offset, :query_factory
|
40
|
+
|
41
|
+
def most_recent_comment_data(username, count, offset)
|
42
|
+
return [] if username == "[deleted]"
|
43
|
+
query = build_query(username, count, offset)
|
44
|
+
client.get(query)
|
45
|
+
query.captured_records
|
46
|
+
end
|
47
|
+
|
48
|
+
def build_query(username, count, offset)
|
49
|
+
endpoint = "user/#{username}/comments.json"
|
50
|
+
query_factory.new(count: count,
|
51
|
+
endpoint: endpoint,
|
52
|
+
resource: :comment,
|
53
|
+
offset: offset)
|
54
|
+
end
|
39
55
|
|
40
56
|
def update_progress(comments)
|
41
57
|
if comments.empty?
|
@@ -45,12 +61,6 @@ module RedditApi
|
|
45
61
|
end
|
46
62
|
end
|
47
63
|
|
48
|
-
def most_recent_comment_data(username, count, offset)
|
49
|
-
return [] if username == "[deleted]"
|
50
|
-
endpoint = "user/#{username}/comments.json"
|
51
|
-
client.get(endpoint, count, :comment, offset)
|
52
|
-
end
|
53
|
-
|
54
64
|
def build_all_comments(comments_data)
|
55
65
|
comments_data.map! do |comment_data|
|
56
66
|
build_comment(comment_data)
|
data/lib/reddit_api/posts.rb
CHANGED
@@ -5,6 +5,7 @@ module RedditApi
|
|
5
5
|
def initialize
|
6
6
|
@client = RedditApi::Client.new
|
7
7
|
@post_factory = RedditApi::Post
|
8
|
+
@query_factory = RedditApi::Query
|
8
9
|
end
|
9
10
|
|
10
11
|
def top(subreddit, count)
|
@@ -14,11 +15,19 @@ module RedditApi
|
|
14
15
|
end
|
15
16
|
|
16
17
|
private
|
17
|
-
attr_reader :client, :post_factory
|
18
|
+
attr_reader :client, :post_factory, :query_factory
|
18
19
|
|
19
20
|
def top_data(subreddit, count)
|
21
|
+
query = build_query(subreddit, count)
|
22
|
+
client.get(query)
|
23
|
+
query.captured_records
|
24
|
+
end
|
25
|
+
|
26
|
+
def build_query(subreddit, count)
|
20
27
|
endpoint = URI.encode("r/#{subreddit.name}/hot.json")
|
21
|
-
|
28
|
+
query_factory.new(count: count,
|
29
|
+
endpoint: endpoint,
|
30
|
+
resource: :post)
|
22
31
|
end
|
23
32
|
|
24
33
|
def filter_out(posts_data, filter)
|
@@ -0,0 +1,56 @@
|
|
1
|
+
|
2
|
+
module RedditApi
|
3
|
+
class Query
|
4
|
+
|
5
|
+
attr_reader :count, :endpoint, :offset_id, :resource_type
|
6
|
+
|
7
|
+
def initialize(args = {})
|
8
|
+
@count = args.fetch(:count)
|
9
|
+
@endpoint = args.fetch(:endpoint, "")
|
10
|
+
@offset_id = args.fetch(:offset, "")
|
11
|
+
@records = args.fetch(:records, {})
|
12
|
+
@resource_type = args.fetch(:resource, "")
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_records(new_records)
|
16
|
+
if count > 1
|
17
|
+
add_multiple_records(new_records)
|
18
|
+
else
|
19
|
+
add_single_record(new_records)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def captured_records
|
24
|
+
records.values
|
25
|
+
end
|
26
|
+
|
27
|
+
def capture_count
|
28
|
+
records.length
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
attr_writer :offset_id
|
33
|
+
private
|
34
|
+
attr_reader :records
|
35
|
+
|
36
|
+
def add_multiple_records(new_records)
|
37
|
+
new_records.each do |record|
|
38
|
+
record_id = record["data"]["id"]
|
39
|
+
records[record_id] = record
|
40
|
+
update_offset_id(record_id)
|
41
|
+
break if records.length == count
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_single_record(record)
|
46
|
+
record_id = record["id"]
|
47
|
+
records[record_id] = record
|
48
|
+
update_offset_id(record_id)
|
49
|
+
end
|
50
|
+
|
51
|
+
def update_offset_id(record_id)
|
52
|
+
self.offset_id = record_id
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
data/lib/reddit_api/requestor.rb
CHANGED
@@ -2,66 +2,54 @@
|
|
2
2
|
module RedditApi
|
3
3
|
class Requestor
|
4
4
|
|
5
|
-
MAXIMUM_RECORDS = 100
|
6
|
-
|
7
5
|
def initialize(args = {})
|
8
|
-
@client = args.fetch(:client, HTTParty)
|
9
6
|
@agent = ENV["REDDIT_AGENT"]
|
7
|
+
@base_url = "https://oauth.reddit.com/"
|
8
|
+
@client = args.fetch(:client, HTTParty)
|
10
9
|
@id = ENV["REDDIT_ID"]
|
11
10
|
@password = ENV["REDDIT_PASSWORD"]
|
12
11
|
@secret = ENV["REDDIT_SECRET"]
|
13
12
|
@username = ENV["REDDIT_USERNAME"]
|
14
|
-
@base_url = "https://oauth.reddit.com/"
|
15
13
|
end
|
16
14
|
|
17
|
-
def build(
|
18
|
-
url = base_url + endpoint
|
15
|
+
def build(query)
|
16
|
+
url = base_url + query.endpoint
|
19
17
|
headers = generate_headers
|
20
|
-
|
21
|
-
[url, { headers: headers, query:
|
18
|
+
api_query = generate_query(query)
|
19
|
+
[url, { headers: headers, query: api_query }]
|
22
20
|
end
|
23
21
|
|
24
22
|
private
|
25
|
-
attr_reader :agent, :base_url, :id, :password, :secret, :username
|
23
|
+
attr_reader :agent, :base_url, :client, :id, :password, :secret, :username
|
26
24
|
|
27
25
|
def generate_headers
|
28
|
-
access_token = generate_access_token
|
29
26
|
{
|
30
27
|
"Authorization" => "bearer #{access_token}",
|
31
28
|
"user-agent" => agent
|
32
29
|
}
|
33
30
|
end
|
34
31
|
|
35
|
-
def generate_query(
|
32
|
+
def generate_query(query)
|
36
33
|
{
|
37
|
-
limit:
|
38
|
-
after: generate_after(resource_type,
|
34
|
+
limit: query.count,
|
35
|
+
after: generate_after(query.resource_type, query.offset_id)
|
39
36
|
}
|
40
37
|
end
|
41
38
|
|
42
|
-
def generate_after(resource_type,
|
43
|
-
if
|
44
|
-
build_after(resource_type,
|
39
|
+
def generate_after(resource_type, offset_id)
|
40
|
+
if offset_id
|
41
|
+
build_after(resource_type, offset_id)
|
45
42
|
else
|
46
43
|
""
|
47
44
|
end
|
48
45
|
end
|
49
46
|
|
50
|
-
def build_after(resource_type,
|
47
|
+
def build_after(resource_type, offset_id)
|
51
48
|
prefix = TYPE_PREFIXES[resource_type]
|
52
|
-
|
53
|
-
"#{prefix}_#{last_resource_id}"
|
54
|
-
end
|
55
|
-
|
56
|
-
def record_id(record)
|
57
|
-
if record.is_a?(Hash)
|
58
|
-
record["data"]["id"]
|
59
|
-
else
|
60
|
-
record
|
61
|
-
end
|
49
|
+
"#{prefix}_#{offset_id}"
|
62
50
|
end
|
63
51
|
|
64
|
-
def
|
52
|
+
def access_token
|
65
53
|
url = "https://www.reddit.com/api/v1/access_token"
|
66
54
|
basic_auth = { username: id,
|
67
55
|
password: secret }
|
@@ -0,0 +1,48 @@
|
|
1
|
+
|
2
|
+
module RedditApi
|
3
|
+
module ResponseParser
|
4
|
+
class << self
|
5
|
+
|
6
|
+
ERROR_CODES = (400..511)
|
7
|
+
|
8
|
+
def parse_response(response, count)
|
9
|
+
if bad_response?(response)
|
10
|
+
handle_bad_response(count)
|
11
|
+
else
|
12
|
+
handle_successful_response(response, count)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def bad_response?(response)
|
19
|
+
ERROR_CODES.cover?(response.code) || response["error"]
|
20
|
+
end
|
21
|
+
|
22
|
+
def handle_bad_response(count)
|
23
|
+
if count > 1
|
24
|
+
[]
|
25
|
+
else
|
26
|
+
{}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def handle_successful_response(response, count)
|
31
|
+
if count > 1
|
32
|
+
handle_plural_response(response)
|
33
|
+
else
|
34
|
+
handle_singular_response(response)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def handle_plural_response(response)
|
39
|
+
response["data"]["children"]
|
40
|
+
end
|
41
|
+
|
42
|
+
def handle_singular_response(response)
|
43
|
+
response["data"]
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -5,6 +5,7 @@ module RedditApi
|
|
5
5
|
def initialize
|
6
6
|
@client = RedditApi::Client.new
|
7
7
|
@subreddit_factory = RedditApi::Subreddit
|
8
|
+
@query_factory = RedditApi::Query
|
8
9
|
end
|
9
10
|
|
10
11
|
def top(count)
|
@@ -13,27 +14,42 @@ module RedditApi
|
|
13
14
|
end
|
14
15
|
|
15
16
|
def data_for(subreddit)
|
16
|
-
|
17
|
-
|
18
|
-
build_subreddit(
|
17
|
+
query = build_singular_query(subreddit)
|
18
|
+
client.get(query)
|
19
|
+
build_subreddit(query.captured_records.first)
|
19
20
|
end
|
20
21
|
|
21
22
|
private
|
22
|
-
attr_reader :client, :subreddit_factory
|
23
|
+
attr_reader :client, :subreddit_factory, :query_factory
|
23
24
|
|
24
25
|
def top_data(count)
|
26
|
+
query = build_plural_query(count)
|
27
|
+
client.get(query)
|
28
|
+
query.captured_records
|
29
|
+
end
|
30
|
+
|
31
|
+
def build_plural_query(count)
|
25
32
|
endpoint = "subreddits/popular.json"
|
26
|
-
|
33
|
+
query_factory.new(count: count,
|
34
|
+
endpoint: endpoint,
|
35
|
+
resource: :subreddit)
|
36
|
+
end
|
37
|
+
|
38
|
+
def build_singular_query(subreddit)
|
39
|
+
endpoint = "r/#{subreddit.name}/about.json"
|
40
|
+
query_factory.new(count: 1,
|
41
|
+
endpoint: endpoint,
|
42
|
+
resource: :subreddit)
|
27
43
|
end
|
28
44
|
|
29
45
|
def build_all_subreddits(subreddits_data)
|
30
46
|
subreddits_data.map! do |subreddit_data|
|
31
|
-
build_subreddit(subreddit_data)
|
47
|
+
build_subreddit(subreddit_data["data"])
|
32
48
|
end
|
33
49
|
end
|
34
50
|
|
35
51
|
def build_subreddit(subreddit_data)
|
36
|
-
subreddit_factory.new(subreddit_data
|
52
|
+
subreddit_factory.new(subreddit_data)
|
37
53
|
end
|
38
54
|
|
39
55
|
end
|
data/lib/reddit_api/version.rb
CHANGED
data/lib/reddit_api.rb
CHANGED
@@ -2,7 +2,9 @@ require "reddit_api/version"
|
|
2
2
|
require "dotenv/load"
|
3
3
|
require "reddit_api/null_response"
|
4
4
|
require "reddit_api/resource_type_prefixes"
|
5
|
+
require "reddit_api/query"
|
5
6
|
require "reddit_api/requestor"
|
7
|
+
require "reddit_api/response_parser"
|
6
8
|
require "reddit_api/client"
|
7
9
|
require "reddit_api/subreddits"
|
8
10
|
require "reddit_api/subreddit"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reddit_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anthony Fuentes
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-02-
|
11
|
+
date: 2017-02-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dotenv
|
@@ -149,8 +149,10 @@ files:
|
|
149
149
|
- lib/reddit_api/null_response.rb
|
150
150
|
- lib/reddit_api/post.rb
|
151
151
|
- lib/reddit_api/posts.rb
|
152
|
+
- lib/reddit_api/query.rb
|
152
153
|
- lib/reddit_api/requestor.rb
|
153
154
|
- lib/reddit_api/resource_type_prefixes.rb
|
155
|
+
- lib/reddit_api/response_parser.rb
|
154
156
|
- lib/reddit_api/subreddit.rb
|
155
157
|
- lib/reddit_api/subreddits.rb
|
156
158
|
- lib/reddit_api/user.rb
|