sideko_hacker_news 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/sideko_hacker_news.rb +259 -118
  3. metadata +8 -43
  4. data/lib/schemas.rb +0 -157
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ef178a860465610752cc33330438201f920004ba291de4b1096e78fb008195a8
4
- data.tar.gz: e4c4c378fd1c24431b2d317f8f939d5a5631ba2c638d2e298e9801e87915784a
3
+ metadata.gz: bd4caa1413f271609180311354ca586ea6ffe7ec01a70e94de54c14918ea19cf
4
+ data.tar.gz: 31087653cab1a2db2570ae271278e15a791fd00454cecdad3df2ce9ca3fa8f65
5
5
  SHA512:
6
- metadata.gz: 6fcf7a3adf6293e26f3ab4390eee3ac944bacc051759278ca77c041cbed515c404517a3067da18960ec30417b6506e92db1a9e7dfae3e34d3dd4be3caeb3b0b5
7
- data.tar.gz: ae27e4a6f5fd26bbf2672aaa65c06430c0610cf2d8779e555bd204fd46bb5720a6d7315875724dd5167f0a8e27d94dce92454a5241500460813d5bd78ba8c36e
6
+ metadata.gz: 30c22b2cfa6cea1f4c3874220b2dc165d802dc97173728e274635f490831bf8bf04a7160a0e66ca664ca343fdbb8f05054ab4c95c37e747a860b143c6ee84e0a
7
+ data.tar.gz: 141b84970c299dd058348d2a53e246032f03b235e790fff2b41614064fff9b2999a2c0aaa4c2b09d23e47acbb02263690a10e24b0fdbf98ed5e13af71001704f
@@ -2,7 +2,6 @@
2
2
  # frozen_string_literal: true
3
3
  require 'json'
4
4
  require 'http'
5
- require_relative 'schemas'
6
5
 
7
6
  class RequestError < StandardError
8
7
  attr_reader :status_code, :method, :url, :data
@@ -21,40 +20,149 @@ class RequestError < StandardError
21
20
  end
22
21
  end
23
22
 
23
+ module AuthProvider
24
+ def add_auth(http_client, req_kwargs)
25
+ raise NotImplementedError, "You must implement the 'add_auth' method"
26
+ end
27
+ end
28
+
29
+ class AuthBasic
30
+ include AuthProvider
31
+
32
+ attr_accessor :username, :password
33
+
34
+ def initialize(username: nil, password: nil)
35
+ @username = username
36
+ @password = password
37
+ end
38
+
39
+ def add_auth(http_client, req_kwargs)
40
+ if !@username.nil? && !@password.nil?
41
+ http_client = http_client.basic_auth(user: @username, pass: @password)
42
+ end
43
+
44
+ return http_client, req_kwargs
45
+ end
46
+ end
47
+
48
+ class AuthBearer
49
+ include AuthProvider
50
+
51
+ attr_accessor :val
52
+
53
+ def initialize(val: nil)
54
+ @val = val
55
+ end
56
+
57
+ def add_auth(http_client, req_kwargs)
58
+ if !@val.nil?
59
+ headers = req_kwargs.fetch(:headers, {})
60
+ headers["Authorization"] = "Bearer " + @val
61
+ req_kwargs[:headers] = headers
62
+ end
63
+
64
+ return http_client, req_kwargs
65
+ end
66
+ end
67
+
68
+ class AuthKeyQuery
69
+ include AuthProvider
70
+
71
+ attr_accessor :query_name, :val
72
+
73
+ def initialize(query_name: nil, val: nil)
74
+ @query_name = query_name
75
+ @val = val
76
+ end
77
+
78
+ def add_auth(http_client, req_kwargs)
79
+ if !val.nil?
80
+ params = req_kwargs.fetch(:params, {})
81
+ params[query_name] = val
82
+ req_kwargs[:params] = params
83
+ end
84
+
85
+ return http_client, req_kwargs
86
+ end
87
+ end
88
+
89
+ class AuthKeyHeader
90
+ include AuthProvider
91
+
92
+ attr_accessor :header_name, :val
93
+
94
+ def initialize(header_name: nil, val: nil)
95
+ @header_name = header_name
96
+ @val = val
97
+ end
98
+
99
+ def add_auth(http_client, req_kwargs)
100
+ if !@val.nil?
101
+ headers = req_kwargs.fetch(:headers, {})
102
+ headers[@header_name] = @val
103
+ req_kwargs[:headers] = headers
104
+ end
105
+
106
+ return http_client, req_kwargs
107
+ end
108
+ end
109
+
110
+ class AuthKeyCookie
111
+ include AuthProvider
112
+
113
+ attr_accessor :cookie_name, :val
114
+
115
+ def initialize(cookie_name: nil, val: nil)
116
+ @cookie_name = cookie_name
117
+ @val = val
118
+ end
119
+
120
+ def add_auth(http_client, req_kwargs)
121
+ if !@val.nil?
122
+ http_client = http_client.cookies(@cookie_name => @val)
123
+ end
124
+
125
+ return http_client, req_kwargs
126
+ end
127
+ end
128
+
24
129
  class Client
25
- def initialize(base_url='https://hacker-news.firebaseio.com/v0')
26
- @_client = HTTP.persistent(nil)
130
+ def initialize(base_url: 'https://hacker-news.firebaseio.com/v0')
27
131
  @_base_url = base_url
132
+ # register auth providers
133
+ @_auth = {}
28
134
  end
29
135
 
30
- def _cast_array(input_array, target_class)
31
- casted = []
32
- input_array.each { |el|
33
- if el.class == Array
34
- casted.append(_cast_array(el, target_class))
35
- else
36
- casted.append(target_class.from_json!(JSON.generate(el)))
37
- end
38
- }
39
- casted
136
+ def _client_with_auth(auth_names, **req_kwargs)
137
+ http_client = HTTP
138
+ auth_names.each do |auth_name|
139
+ provider = @_auth[auth_name]
140
+ http_client, req_kwargs = provider.add_auth(http_client, req_kwargs) if provider
141
+ end
142
+
143
+ return http_client, req_kwargs
40
144
  end
41
145
 
42
146
  def get_ask_story_ids(print: nil)
43
- url = @_base_url + "/askstories.json"
44
- params = {}
147
+ _url = @_base_url + "/askstories.json"
148
+ _kwargs = {
149
+ params: {}
150
+ }
45
151
  if print != nil
46
- params[:print] = print
152
+ _kwargs[:params][:"print"] = print
47
153
  end
154
+ _http_client, _req_kwargs = self._client_with_auth(
155
+ [],
156
+ **_kwargs
157
+ )
48
158
 
49
159
 
50
- response = @_client.get(
51
- url,
52
- :params => params,
160
+ response = _http_client.get(
161
+ _url,
53
162
 
163
+ **_req_kwargs
54
164
  )
55
- if response.status.success?
56
- response = response.parse
57
- else
165
+ if !response.status.success?
58
166
  raise RequestError.new(
59
167
  status_code=response.status,
60
168
  method="get",
@@ -63,25 +171,29 @@ class Client
63
171
  )
64
172
  end
65
173
 
66
- response
174
+ return response.parse
67
175
  end
68
176
 
69
177
  def get_best_story_ids(print: nil)
70
- url = @_base_url + "/beststories.json"
71
- params = {}
178
+ _url = @_base_url + "/beststories.json"
179
+ _kwargs = {
180
+ params: {}
181
+ }
72
182
  if print != nil
73
- params[:print] = print
183
+ _kwargs[:params][:"print"] = print
74
184
  end
185
+ _http_client, _req_kwargs = self._client_with_auth(
186
+ [],
187
+ **_kwargs
188
+ )
75
189
 
76
190
 
77
- response = @_client.get(
78
- url,
79
- :params => params,
191
+ response = _http_client.get(
192
+ _url,
80
193
 
194
+ **_req_kwargs
81
195
  )
82
- if response.status.success?
83
- response = response.parse
84
- else
196
+ if !response.status.success?
85
197
  raise RequestError.new(
86
198
  status_code=response.status,
87
199
  method="get",
@@ -90,25 +202,29 @@ class Client
90
202
  )
91
203
  end
92
204
 
93
- response
205
+ return response.parse
94
206
  end
95
207
 
96
- def get_item(id:, print: nil)
97
- url = @_base_url + "/item/#{id}.json"
98
- params = {}
208
+ def get_item(id, print: nil)
209
+ _url = @_base_url + "/item/#{id}.json"
210
+ _kwargs = {
211
+ params: {}
212
+ }
99
213
  if print != nil
100
- params[:print] = print
214
+ _kwargs[:params][:"print"] = print
101
215
  end
216
+ _http_client, _req_kwargs = self._client_with_auth(
217
+ [],
218
+ **_kwargs
219
+ )
102
220
 
103
221
 
104
- response = @_client.get(
105
- url,
106
- :params => params,
222
+ response = _http_client.get(
223
+ _url,
107
224
 
225
+ **_req_kwargs
108
226
  )
109
- if response.status.success?
110
- response = response.parse
111
- else
227
+ if !response.status.success?
112
228
  raise RequestError.new(
113
229
  status_code=response.status,
114
230
  method="get",
@@ -117,26 +233,29 @@ class Client
117
233
  )
118
234
  end
119
235
 
120
- response = Item.from_dynamic!(response)
121
- response
236
+ return response.parse
122
237
  end
123
238
 
124
239
  def get_job_story_ids(print: nil)
125
- url = @_base_url + "/jobstories.json"
126
- params = {}
240
+ _url = @_base_url + "/jobstories.json"
241
+ _kwargs = {
242
+ params: {}
243
+ }
127
244
  if print != nil
128
- params[:print] = print
245
+ _kwargs[:params][:"print"] = print
129
246
  end
247
+ _http_client, _req_kwargs = self._client_with_auth(
248
+ [],
249
+ **_kwargs
250
+ )
130
251
 
131
252
 
132
- response = @_client.get(
133
- url,
134
- :params => params,
253
+ response = _http_client.get(
254
+ _url,
135
255
 
256
+ **_req_kwargs
136
257
  )
137
- if response.status.success?
138
- response = response.parse
139
- else
258
+ if !response.status.success?
140
259
  raise RequestError.new(
141
260
  status_code=response.status,
142
261
  method="get",
@@ -145,25 +264,29 @@ class Client
145
264
  )
146
265
  end
147
266
 
148
- response
267
+ return response.parse
149
268
  end
150
269
 
151
270
  def get_max_item_id(print: nil)
152
- url = @_base_url + "/maxitem.json"
153
- params = {}
271
+ _url = @_base_url + "/maxitem.json"
272
+ _kwargs = {
273
+ params: {}
274
+ }
154
275
  if print != nil
155
- params[:print] = print
276
+ _kwargs[:params][:"print"] = print
156
277
  end
278
+ _http_client, _req_kwargs = self._client_with_auth(
279
+ [],
280
+ **_kwargs
281
+ )
157
282
 
158
283
 
159
- response = @_client.get(
160
- url,
161
- :params => params,
284
+ response = _http_client.get(
285
+ _url,
162
286
 
287
+ **_req_kwargs
163
288
  )
164
- if response.status.success?
165
- response = response.parse
166
- else
289
+ if !response.status.success?
167
290
  raise RequestError.new(
168
291
  status_code=response.status,
169
292
  method="get",
@@ -172,25 +295,29 @@ class Client
172
295
  )
173
296
  end
174
297
 
175
- response
298
+ return response.parse
176
299
  end
177
300
 
178
301
  def get_new_story_ids(print: nil)
179
- url = @_base_url + "/newstories.json"
180
- params = {}
302
+ _url = @_base_url + "/newstories.json"
303
+ _kwargs = {
304
+ params: {}
305
+ }
181
306
  if print != nil
182
- params[:print] = print
307
+ _kwargs[:params][:"print"] = print
183
308
  end
309
+ _http_client, _req_kwargs = self._client_with_auth(
310
+ [],
311
+ **_kwargs
312
+ )
184
313
 
185
314
 
186
- response = @_client.get(
187
- url,
188
- :params => params,
315
+ response = _http_client.get(
316
+ _url,
189
317
 
318
+ **_req_kwargs
190
319
  )
191
- if response.status.success?
192
- response = response.parse
193
- else
320
+ if !response.status.success?
194
321
  raise RequestError.new(
195
322
  status_code=response.status,
196
323
  method="get",
@@ -199,25 +326,29 @@ class Client
199
326
  )
200
327
  end
201
328
 
202
- response
329
+ return response.parse
203
330
  end
204
331
 
205
332
  def get_show_story_ids(print: nil)
206
- url = @_base_url + "/showstories.json"
207
- params = {}
333
+ _url = @_base_url + "/showstories.json"
334
+ _kwargs = {
335
+ params: {}
336
+ }
208
337
  if print != nil
209
- params[:print] = print
338
+ _kwargs[:params][:"print"] = print
210
339
  end
340
+ _http_client, _req_kwargs = self._client_with_auth(
341
+ [],
342
+ **_kwargs
343
+ )
211
344
 
212
345
 
213
- response = @_client.get(
214
- url,
215
- :params => params,
346
+ response = _http_client.get(
347
+ _url,
216
348
 
349
+ **_req_kwargs
217
350
  )
218
- if response.status.success?
219
- response = response.parse
220
- else
351
+ if !response.status.success?
221
352
  raise RequestError.new(
222
353
  status_code=response.status,
223
354
  method="get",
@@ -226,25 +357,29 @@ class Client
226
357
  )
227
358
  end
228
359
 
229
- response
360
+ return response.parse
230
361
  end
231
362
 
232
363
  def get_top_story_ids(print: nil)
233
- url = @_base_url + "/topstories.json"
234
- params = {}
364
+ _url = @_base_url + "/topstories.json"
365
+ _kwargs = {
366
+ params: {}
367
+ }
235
368
  if print != nil
236
- params[:print] = print
369
+ _kwargs[:params][:"print"] = print
237
370
  end
371
+ _http_client, _req_kwargs = self._client_with_auth(
372
+ [],
373
+ **_kwargs
374
+ )
238
375
 
239
376
 
240
- response = @_client.get(
241
- url,
242
- :params => params,
377
+ response = _http_client.get(
378
+ _url,
243
379
 
380
+ **_req_kwargs
244
381
  )
245
- if response.status.success?
246
- response = response.parse
247
- else
382
+ if !response.status.success?
248
383
  raise RequestError.new(
249
384
  status_code=response.status,
250
385
  method="get",
@@ -253,25 +388,29 @@ class Client
253
388
  )
254
389
  end
255
390
 
256
- response
391
+ return response.parse
257
392
  end
258
393
 
259
394
  def get_updates(print: nil)
260
- url = @_base_url + "/updates.json"
261
- params = {}
395
+ _url = @_base_url + "/updates.json"
396
+ _kwargs = {
397
+ params: {}
398
+ }
262
399
  if print != nil
263
- params[:print] = print
400
+ _kwargs[:params][:"print"] = print
264
401
  end
402
+ _http_client, _req_kwargs = self._client_with_auth(
403
+ [],
404
+ **_kwargs
405
+ )
265
406
 
266
407
 
267
- response = @_client.get(
268
- url,
269
- :params => params,
408
+ response = _http_client.get(
409
+ _url,
270
410
 
411
+ **_req_kwargs
271
412
  )
272
- if response.status.success?
273
- response = response.parse
274
- else
413
+ if !response.status.success?
275
414
  raise RequestError.new(
276
415
  status_code=response.status,
277
416
  method="get",
@@ -280,26 +419,29 @@ class Client
280
419
  )
281
420
  end
282
421
 
283
- response = GetUpdatesJSONResponse.from_dynamic!(response)
284
- response
422
+ return response.parse
285
423
  end
286
424
 
287
- def get_user(id:, print: nil)
288
- url = @_base_url + "/user/#{id}.json"
289
- params = {}
425
+ def get_user(id, print: nil)
426
+ _url = @_base_url + "/user/#{id}.json"
427
+ _kwargs = {
428
+ params: {}
429
+ }
290
430
  if print != nil
291
- params[:print] = print
431
+ _kwargs[:params][:"print"] = print
292
432
  end
433
+ _http_client, _req_kwargs = self._client_with_auth(
434
+ [],
435
+ **_kwargs
436
+ )
293
437
 
294
438
 
295
- response = @_client.get(
296
- url,
297
- :params => params,
439
+ response = _http_client.get(
440
+ _url,
298
441
 
442
+ **_req_kwargs
299
443
  )
300
- if response.status.success?
301
- response = response.parse
302
- else
444
+ if !response.status.success?
303
445
  raise RequestError.new(
304
446
  status_code=response.status,
305
447
  method="get",
@@ -308,8 +450,7 @@ class Client
308
450
  )
309
451
  end
310
452
 
311
- response = User.from_dynamic!(response)
312
- response
453
+ return response.parse
313
454
  end
314
455
 
315
456
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sideko_hacker_news
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sideko
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-10-12 00:00:00.000000000 Z
11
+ date: 2023-12-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http
@@ -24,40 +24,6 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: 5.1.1
27
- - !ruby/object:Gem::Dependency
28
- name: dry-struct
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '1.6'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '1.6'
41
- - !ruby/object:Gem::Dependency
42
- name: dry-types
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '1.7'
48
- - - ">="
49
- - !ruby/object:Gem::Version
50
- version: 1.7.1
51
- type: :runtime
52
- prerelease: false
53
- version_requirements: !ruby/object:Gem::Requirement
54
- requirements:
55
- - - "~>"
56
- - !ruby/object:Gem::Version
57
- version: '1.7'
58
- - - ">="
59
- - !ruby/object:Gem::Version
60
- version: 1.7.1
61
27
  description: |
62
28
  Hacker News makes the public their data available in near real time.
63
29
  &gt; The v0 API is essentially a dump of our in-memory data structures. We know, what works great locally in memory isn&#x27;t so hot over the network. Many of the awkward things are just the way HN works internally... It&#x27;s not the ideal public API, but it&#x27;s the one we could release in the time we had
@@ -70,13 +36,12 @@ executables: []
70
36
  extensions: []
71
37
  extra_rdoc_files: []
72
38
  files:
73
- - lib/schemas.rb
74
39
  - lib/sideko_hacker_news.rb
75
- homepage:
40
+ homepage:
76
41
  licenses:
77
42
  - MIT
78
43
  metadata: {}
79
- post_install_message:
44
+ post_install_message:
80
45
  rdoc_options: []
81
46
  require_paths:
82
47
  - lib
@@ -91,8 +56,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
91
56
  - !ruby/object:Gem::Version
92
57
  version: '0'
93
58
  requirements: []
94
- rubygems_version: 3.4.10
95
- signing_key:
59
+ rubygems_version: 3.3.5
60
+ signing_key:
96
61
  specification_version: 4
97
- summary: sideko_hacker_news 0.1.0
62
+ summary: sideko_hacker_news 0.2.0
98
63
  test_files: []
data/lib/schemas.rb DELETED
@@ -1,157 +0,0 @@
1
-
2
- require 'json'
3
- require 'dry-types'
4
- require 'dry-struct'
5
-
6
- module Types
7
- include Dry.Types(default: :nominal)
8
-
9
- Integer = Strict::Integer
10
- Bool = Strict::Bool
11
- Hash = Strict::Hash
12
- String = Strict::String
13
- end
14
-
15
- class GetUpdatesJSONResponse < Dry::Struct
16
-
17
- # Changed items
18
- attribute :items, Types.Array(Types::Integer).optional
19
-
20
- # Changed profiles
21
- attribute :profiles, Types.Array(Types::String).optional
22
-
23
- def self.from_dynamic!(d)
24
- d = Types::Hash[d]
25
- new(
26
- items: d["items"],
27
- profiles: d["profiles"],
28
- )
29
- end
30
-
31
- def self.from_json!(json)
32
- from_dynamic!(JSON.parse(json))
33
- end
34
-
35
- def to_dynamic
36
- {
37
- "items" => items,
38
- "profiles" => profiles,
39
- }
40
- end
41
-
42
- def to_json(options = nil)
43
- JSON.generate(to_dynamic, options)
44
- end
45
- end
46
-
47
- class Item < Dry::Struct
48
- attribute :by, Types::String
49
- attribute :dead, Types::Bool.optional
50
- attribute :deleted, Types::Bool.optional
51
- attribute :descendants, Types::Integer.optional
52
- attribute :id, Types::Integer
53
- attribute :kids, Types.Array(Types::Integer).optional
54
- attribute :parent, Types::Integer.optional
55
- attribute :parts, Types.Array(Types::Integer).optional
56
- attribute :poll, Types::Integer.optional
57
- attribute :score, Types::Integer.optional
58
- attribute :text, Types::String.optional
59
- attribute :time, Types::Integer
60
- attribute :title, Types::String.optional
61
- attribute :item_type, Types::String
62
- attribute :url, Types::String.optional
63
-
64
- def self.from_dynamic!(d)
65
- d = Types::Hash[d]
66
- new(
67
- by: d.fetch("by"),
68
- dead: d["dead"],
69
- deleted: d["deleted"],
70
- descendants: d["descendants"],
71
- id: d.fetch("id"),
72
- kids: d["kids"],
73
- parent: d["parent"],
74
- parts: d["parts"],
75
- poll: d["poll"],
76
- score: d["score"],
77
- text: d["text"],
78
- time: d.fetch("time"),
79
- title: d["title"],
80
- item_type: d.fetch("type"),
81
- url: d["url"],
82
- )
83
- end
84
-
85
- def self.from_json!(json)
86
- from_dynamic!(JSON.parse(json))
87
- end
88
-
89
- def to_dynamic
90
- {
91
- "by" => by,
92
- "dead" => dead,
93
- "deleted" => deleted,
94
- "descendants" => descendants,
95
- "id" => id,
96
- "kids" => kids,
97
- "parent" => parent,
98
- "parts" => parts,
99
- "poll" => poll,
100
- "score" => score,
101
- "text" => text,
102
- "time" => time,
103
- "title" => title,
104
- "type" => item_type,
105
- "url" => url,
106
- }
107
- end
108
-
109
- def to_json(options = nil)
110
- JSON.generate(to_dynamic, options)
111
- end
112
- end
113
-
114
- class User < Dry::Struct
115
-
116
- # The user's optional self-description. HTML
117
- attribute :about, Types::String.optional
118
-
119
- # Creation date of the user, in Unix Time
120
- attribute :created, Types::Integer.optional
121
-
122
- attribute :id, Types::String.optional
123
-
124
- # The user's karma
125
- attribute :karma, Types::Integer.optional
126
-
127
- attribute :submitted, Types::Any.optional
128
-
129
- def self.from_dynamic!(d)
130
- d = Types::Hash[d]
131
- new(
132
- about: d["about"],
133
- created: d["created"],
134
- id: d["id"],
135
- karma: d["karma"],
136
- submitted: d["submitted"],
137
- )
138
- end
139
-
140
- def self.from_json!(json)
141
- from_dynamic!(JSON.parse(json))
142
- end
143
-
144
- def to_dynamic
145
- {
146
- "about" => about,
147
- "created" => created,
148
- "id" => id,
149
- "karma" => karma,
150
- "submitted" => submitted,
151
- }
152
- end
153
-
154
- def to_json(options = nil)
155
- JSON.generate(to_dynamic, options)
156
- end
157
- end