reddit_api 0.1.18 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fff7c79ae95004afc62a96034a80d48fdb33d9c5
4
- data.tar.gz: 00e2b4d24fe666eb5bc55a885073dcaf56089c75
3
+ metadata.gz: e2c1a49844a77703602af21827434a0d54f4db28
4
+ data.tar.gz: d59933c5bbeb7b06c38bf1319c99ed6e343317e8
5
5
  SHA512:
6
- metadata.gz: 731f3fa32a0fdf3d3a832b54fdcc300e29046f1a303e68cd59192154b8aa4642689a116d9efdbfffa184b9de77d4cdb462f898887a0790ade90427f7b5670d45
7
- data.tar.gz: bc467855c109fa8eb474fdd58f6d42bef2e1127da3e66bedd0d16138f550df981bba3c0f9132735b0787562d0e47dbcb6a2c47021af2e373bb956935c9a3a7c5
6
+ metadata.gz: 6a631d30ae80980cab7ba975181c0e015da0abe7a98004f317f435fc99c92630c9cb93cddb063899f291cc4cd18b78cf032e64826c3f19a5506b9b012a1738d1
7
+ data.tar.gz: 7ff3eda53055f62798f0344de7debca41da2e541806248d007ae0e9450f8a2ce0434c8872b5956909215ae0f186b132dc2c40c7634b193dab9982578ebc6c59e
@@ -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
- @failures = args.fetch(:failures, 0)
22
+ @parser = args.fetch(:parser, RedditApi::ResponseParser)
24
23
  @null_response_factory = RedditApi:: NullResponse
25
- @last_record = nil
24
+ @failures = args.fetch(:failures, 0)
26
25
  end
27
26
 
28
- def get(endpoint, count, resource_type, offset = nil)
29
- if count > 1
30
- get_many(endpoint, count, resource_type, offset)
31
- else
32
- get_one(endpoint, count, resource_type)
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, :last_record
37
+ attr_writer :failures
38
38
  private
39
- attr_reader :client, :base_url, :null_response_factory, :last_record,
40
- :requestor
39
+ attr_reader :client, :null_response_factory, :requestor, :parser
41
40
 
42
- def get_many(endpoint, count, resource_type, offset)
41
+ def send_request(query)
43
42
  sleep(SLEEP_TIME)
44
- records = {}
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 parse_response(response, count)
82
- if bad_response?(response)
83
- handle_bad_response(count)
84
- else
85
- handle_successful_response(response, count)
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 bad_response?(response)
90
- ERROR_CODES.cover?(response.code) || response["error"]
55
+ def update_query(query, response)
56
+ query.add_records(response)
91
57
  end
92
58
 
93
- def handle_bad_response(count)
94
- self.failures += 1
95
- if count > 1
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 handle_successful_response(response, count)
103
- if count > 1
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
@@ -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 = 100, offset = nil)
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)
@@ -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
- client.get(endpoint, count, :post)
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
@@ -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(endpoint, resource_type, last_record = nil)
18
- url = base_url + endpoint
15
+ def build(query)
16
+ url = base_url + query.endpoint
19
17
  headers = generate_headers
20
- query = generate_query(resource_type, last_record)
21
- [url, { headers: headers, query: 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, :client
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(resource_type, last_record)
32
+ def generate_query(query)
36
33
  {
37
- limit: MAXIMUM_RECORDS,
38
- after: generate_after(resource_type, last_record)
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, last_record)
43
- if last_record
44
- build_after(resource_type, last_record)
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, record)
47
+ def build_after(resource_type, offset_id)
51
48
  prefix = TYPE_PREFIXES[resource_type]
52
- last_resource_id = record_id(record)
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 generate_access_token
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
- endpoint = "r/#{subreddit.name}/about.json"
17
- response = client.get(endpoint, 1, :subreddit)
18
- build_subreddit(response)
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
- client.get(endpoint, count, :subreddit)
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["data"])
52
+ subreddit_factory.new(subreddit_data)
37
53
  end
38
54
 
39
55
  end
@@ -1,3 +1,3 @@
1
1
  module RedditApi
2
- VERSION = "0.1.18"
2
+ VERSION = "0.2.0"
3
3
  end
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.1.18
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-20 00:00:00.000000000 Z
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