metonym 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Gemfile.lock +34 -4
- data/README.md +193 -142
- data/lib/metonym.rb +12 -2
- data/lib/metonym/lib/gnews.rb +49 -47
- data/lib/metonym/lib/news_api.rb +45 -56
- data/lib/metonym/lib/presenters/base_response_presenter.rb +18 -0
- data/lib/metonym/lib/presenters/gnews_response_presenter.rb +5 -0
- data/lib/metonym/lib/presenters/news_api_response_presenter.rb +3 -0
- data/lib/metonym/lib/repositories/base_repository.rb +9 -0
- data/lib/metonym/lib/repositories/gnews_repository.rb +31 -0
- data/lib/metonym/lib/repositories/news_api_repository.rb +31 -0
- data/lib/metonym/lib/validators/base_validator.rb +25 -0
- data/lib/metonym/lib/validators/gnews_query_validator.rb +55 -0
- data/lib/metonym/lib/validators/news_api_query_validator.rb +61 -0
- data/lib/metonym/version.rb +3 -1
- data/metonym.gemspec +24 -22
- metadata +39 -18
- data/lib/metonym/lib/validate.rb +0 -124
data/lib/metonym.rb
CHANGED
@@ -1,8 +1,18 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'metonym/version'
|
2
4
|
require 'date'
|
3
5
|
require 'net/http'
|
4
6
|
require 'metonym/lib/gnews.rb'
|
5
|
-
require 'metonym/lib/
|
7
|
+
require 'metonym/lib/presenters/base_response_presenter.rb'
|
8
|
+
require 'metonym/lib/presenters/gnews_response_presenter.rb'
|
9
|
+
require 'metonym/lib/presenters/news_api_response_presenter.rb'
|
10
|
+
require 'metonym/lib/repositories/base_repository.rb'
|
11
|
+
require 'metonym/lib/repositories/gnews_repository.rb'
|
12
|
+
require 'metonym/lib/repositories/news_api_repository.rb'
|
13
|
+
require 'metonym/lib/validators/base_validator.rb'
|
14
|
+
require 'metonym/lib/validators/gnews_query_validator.rb'
|
15
|
+
require 'metonym/lib/validators/news_api_query_validator.rb'
|
6
16
|
require 'metonym/lib/news_api.rb'
|
7
17
|
require 'byebug'
|
8
18
|
require 'json'
|
data/lib/metonym/lib/gnews.rb
CHANGED
@@ -1,49 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Gnews
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
end
|
4
|
+
class Query
|
5
|
+
attr_accessor :gnews_api_key
|
6
|
+
attr_accessor :uri
|
7
|
+
|
8
|
+
def initialize(key)
|
9
|
+
@gnews_api_key = key
|
10
|
+
@gnews = Gnews::GnewsRepository.new(key)
|
11
|
+
end
|
12
|
+
|
13
|
+
def search(args, **options)
|
14
|
+
request('search', args: args, format: define_response_format(options))
|
15
|
+
end
|
16
|
+
|
17
|
+
def top_news(args, **options)
|
18
|
+
request('top-news', args: args, format: define_response_format(options))
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def define_response_format(options)
|
24
|
+
options[:format] || 'json'
|
25
|
+
end
|
26
|
+
|
27
|
+
def request(resource, args:, format:)
|
28
|
+
validate_query_parameters(args, format)
|
29
|
+
|
30
|
+
case resource
|
31
|
+
when 'search'
|
32
|
+
response = @gnews.search(query: args)
|
33
|
+
when 'top-news'
|
34
|
+
response = @gnews.top_news(query: args)
|
35
|
+
when 'topics'
|
36
|
+
response = @gnews.topics(query: args)
|
37
|
+
end
|
38
|
+
rescue StandardError => e
|
39
|
+
response = { errors: e.to_s }
|
40
|
+
ensure
|
41
|
+
presenter = Gnews::GnewsResponsePresenter.new
|
42
|
+
return presenter.generate_formatted_response(response, format)
|
43
|
+
end
|
44
|
+
|
45
|
+
def validate_query_parameters(args, format)
|
46
|
+
v = Validate::GnewsQueryValidator.new(@gnews_api_key,
|
47
|
+
args: args, format: format)
|
48
|
+
raise v unless v
|
48
49
|
end
|
49
|
-
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/metonym/lib/news_api.rb
CHANGED
@@ -1,65 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module NewsApi
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
attr_accessor :uri
|
4
|
+
class Query
|
5
|
+
attr_accessor :news_api_key
|
6
|
+
attr_accessor :uri
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
8
|
+
def initialize(key)
|
9
|
+
@news_api_key = key
|
10
|
+
@news_api = NewsApi::NewsApiRepository.new(key)
|
11
|
+
end
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
13
|
+
def everything(args, **options)
|
14
|
+
request('everything', args: args, format: define_response_format(options))
|
15
|
+
end
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
17
|
+
def top_headlines(args, **options)
|
18
|
+
request('top-headlines', args: args, format: define_response_format(options))
|
19
|
+
end
|
22
20
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
end
|
21
|
+
def sources(args, **options)
|
22
|
+
request('sources', args: args, format: define_response_format(options))
|
23
|
+
end
|
27
24
|
|
28
|
-
|
29
|
-
def request(args, format, uri, endpoint)
|
30
|
-
begin
|
31
|
-
v = Validate::NewsApiValidator.new
|
32
|
-
raise "API Key is required" if v.is_key_present?(@news_api_key) == false
|
33
|
-
raise "Invalid parameter sequence" if v.is_query_valid?(args, endpoint) == false
|
34
|
-
raise "Invalid country sent" if v.is_country_valid?(args) == false
|
35
|
-
raise "Invalid language sent" if v.is_language_valid?(args) == false
|
36
|
-
raise "Invalid date or dates sent" if v.is_date_valid?(args) == false
|
37
|
-
raise "Invalid format sent" if v.is_format_valid?(format) == false
|
38
|
-
|
39
|
-
args = prepare_arguments(args)
|
25
|
+
private
|
40
26
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
27
|
+
def define_response_format(options)
|
28
|
+
options[:format] || 'json'
|
29
|
+
end
|
30
|
+
|
31
|
+
def request(resource, args:, format:)
|
32
|
+
validate_query_parameters(args, format, resource)
|
33
|
+
|
34
|
+
case resource
|
35
|
+
when 'top-headlines'
|
36
|
+
response = @news_api.top_headlines(query: args)
|
37
|
+
when 'everything'
|
38
|
+
response = @news_api.everything(query: args)
|
39
|
+
when 'sources'
|
40
|
+
response = @news_api.sources(query: args)
|
41
|
+
end
|
42
|
+
rescue StandardError => e
|
43
|
+
response = { errors: e.to_s }
|
44
|
+
ensure
|
45
|
+
presenter = NewsApi::NewsApiResponsePresenter.new
|
46
|
+
return presenter.generate_formatted_response(response, format)
|
47
|
+
end
|
57
48
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
args['to'] = args.has_key?('to') ? args['to'].strftime("%FT%T%:z") : nil
|
62
|
-
args
|
63
|
-
end
|
49
|
+
def validate_query_parameters(args, format, resource)
|
50
|
+
v = Validate::NewsApiQueryValidator.new(@news_api_key, args: args, format: format, endpoint: resource)
|
51
|
+
raise v unless v
|
64
52
|
end
|
65
|
-
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class BaseResponsePresenter
|
4
|
+
def generate_formatted_response(response, format)
|
5
|
+
return response if response.is_a?(Hash) && response.key?(:errors)
|
6
|
+
|
7
|
+
case format
|
8
|
+
when nil
|
9
|
+
response.body
|
10
|
+
when 'json'
|
11
|
+
response.body
|
12
|
+
when 'hash'
|
13
|
+
JSON.parse(response.body)
|
14
|
+
else
|
15
|
+
response.body
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gnews
|
4
|
+
class GnewsRepository < BaseRepository
|
5
|
+
def initialize(api_key)
|
6
|
+
@gnews_api_key = api_key
|
7
|
+
@uri = 'https://gnews.io/api/v3/'
|
8
|
+
end
|
9
|
+
|
10
|
+
def search(query:)
|
11
|
+
request(@uri, query: query, resource: 'search')
|
12
|
+
end
|
13
|
+
|
14
|
+
def top_news(query:)
|
15
|
+
request(@uri, query: query, resource: 'top-news')
|
16
|
+
end
|
17
|
+
|
18
|
+
def topic
|
19
|
+
request(@uri, query: query, resource: 'topic')
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def prepare_arguments(query)
|
25
|
+
query['mindate'] = query.key?(:mindate) ? query[:mindate].strftime('%y-%m-%d') : nil
|
26
|
+
query['maxdate'] = query.key?(:maxdate) ? query[:maxdate].strftime('%y-%m-%d') : nil
|
27
|
+
query['token'] = @gnews_api_key
|
28
|
+
query
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NewsApi
|
4
|
+
class NewsApiRepository < BaseRepository
|
5
|
+
def initialize(api_key)
|
6
|
+
@news_api_key = api_key
|
7
|
+
@uri = 'https://newsapi.org/v2/'
|
8
|
+
end
|
9
|
+
|
10
|
+
def everything(query:)
|
11
|
+
request(@uri, query: query, resource: 'everything')
|
12
|
+
end
|
13
|
+
|
14
|
+
def top_headlines(query:)
|
15
|
+
request(@uri, query: query, resource: 'top-headlines')
|
16
|
+
end
|
17
|
+
|
18
|
+
def sources(query:)
|
19
|
+
request(@uri, query: query, resource: 'sources')
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def prepare_arguments(query)
|
25
|
+
query['from'] = query.key?(:from) ? query[:from].strftime('%FT%T%:z') : nil
|
26
|
+
query['to'] = query.key?(:to) ? query[:to].strftime('%FT%T%:z') : nil
|
27
|
+
query['apiKey'] = @news_api_key
|
28
|
+
query
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Validate
|
4
|
+
class BaseValidator
|
5
|
+
protected
|
6
|
+
|
7
|
+
def key_present?(args)
|
8
|
+
!args.nil?
|
9
|
+
end
|
10
|
+
|
11
|
+
def language_valid?(args)
|
12
|
+
return true if args[:lang].nil?
|
13
|
+
|
14
|
+
[
|
15
|
+
'af', 'ak', 'sq', 'am', 'ar', 'hy', 'az', 'eu', 'be', 'bem', 'bn', 'bs', 'bh', 'br', 'bg', 'km', 'ca', 'chr', 'ny', 'zh-CN',
|
16
|
+
'zh-TW', 'co', 'hr', 'cs', 'da', 'nl', 'en', 'eo', 'et', 'ee', 'fo', 'tl', 'fi', 'fr', 'fy', 'gl', 'ka', 'de', 'el', 'gn', 'gu',
|
17
|
+
'ht', 'ha', 'haw', 'iw', 'hi', 'hu', 'is', 'ig', 'id', 'ia', 'ga', 'it', 'ja', 'jw', 'kn', 'kk', 'rw', 'rn', 'kg', 'ko', 'kri',
|
18
|
+
'ku', 'ckb', 'ky', 'lo', 'la', 'lv', 'ln', 'lt', 'loz', 'lg', 'ach', 'mk', 'mg', 'ms', 'ml', 'mt', 'mi', 'mr', 'mfe', 'mo', 'mn',
|
19
|
+
'sr-ME', 'ne', 'nso', 'no', 'nn', 'oc', 'or', 'om', 'ps', 'fa', 'pl', 'pt-BR', 'pt-PT', 'pa', 'qu', 'ro', 'rm', 'nyn', 'ru', 'gd',
|
20
|
+
'sr', 'sh', 'st', 'tn', 'crs', 'sn', 'sd', 'si', 'sk', 'sl', 'so', 'es', 'sp-419', 'su', 'sw', 'sv', 'tg', 'ta', 'tt', 'te', 'th', 'ti',
|
21
|
+
'to', 'lua', 'tum', 'tr', 'tk', 'tw', 'ug', 'uk', 'ur', 'uz', 'vi', 'cy', 'wo', 'xh', 'yi', 'yo', 'zu'
|
22
|
+
].include?(args[:lang].downcase)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Validate
|
4
|
+
class GnewsQueryValidator < BaseValidator
|
5
|
+
COUNTRIES = %w[
|
6
|
+
af al dz as ad ao ai aq ag ar am aw au at az bs bh bd bb by
|
7
|
+
be bz bj bm bt bo ba bw bv br io bn bg bf bi kh cm ca cv ky
|
8
|
+
cf td cl cn cx cc co km cg cd ck cr ci hr cu cy cz dk dj dm
|
9
|
+
do ec eg sv gq er ee et fk fo fj fi fr gf pf tf ga gm ge de
|
10
|
+
gh gi gr gl gd gp gu gt gn gw gy ht hm va hn hk hu is in id
|
11
|
+
ir iq ie il it jm jp jo kz ke ki kp kr kw kg la lv lb ls lr
|
12
|
+
ly li lt lu mo mk mg mw my mv ml mt mh mq mr mu yt mx fm md
|
13
|
+
mc mn ms ma mz mm na nr np nl an nc nz ni ne ng nu nf mp no
|
14
|
+
om pk pw ps pa pg py pe ph pn pl pt pr qa re ro ru rw sh kn
|
15
|
+
lc pm vc ws sm st sa sn cs sc sl sg sk si sb so za gs sp lk
|
16
|
+
sd sr sj sz se ch sy tw tj tz th tl tg tk to tt tn tr tm tc
|
17
|
+
tv ug ua ae uk us um uy uz vu ve vn vg vi wf eh ye zm zw
|
18
|
+
].freeze
|
19
|
+
|
20
|
+
def initialize(api_key, args:, format:)
|
21
|
+
raise 'API Key is required' unless key_present?(api_key)
|
22
|
+
raise 'Invalid parameter sequence' unless query_valid?(args)
|
23
|
+
raise 'Invalid country sent' unless country_valid?(args)
|
24
|
+
raise 'Invalid language sent' unless language_valid?(args)
|
25
|
+
raise 'Invalid date or dates sent' unless date_valid?(args)
|
26
|
+
|
27
|
+
true
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def query_valid?(args)
|
33
|
+
search_template = %i[q max lang country mindate maxdate in]
|
34
|
+
top_news_template = %i[lang country max image]
|
35
|
+
template = search_template + top_news_template
|
36
|
+
(args.keys - template).empty?
|
37
|
+
end
|
38
|
+
|
39
|
+
def country_valid?(args)
|
40
|
+
args[:country].nil? ? true : COUNTRIES.include?(args[:country].downcase)
|
41
|
+
end
|
42
|
+
|
43
|
+
def date_valid?(args)
|
44
|
+
if args[:mindate].nil? && args[:maxdate].nil?
|
45
|
+
true
|
46
|
+
elsif args[:mindate] && args[:maxdate]
|
47
|
+
(args[:mindate].respond_to?(:strftime) && args[:maxdate].respond_to?(:strftime))
|
48
|
+
elsif args[:mindate] && args[:maxdate].nil?
|
49
|
+
args[:mindate].respond_to?(:strftime)
|
50
|
+
elsif args[:mindate].nil? && args[:maxdate]
|
51
|
+
args[:maxdate].respond_to?(:strftime)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Validate
|
4
|
+
class NewsApiQueryValidator < BaseValidator
|
5
|
+
COUNTRIES = %w[ar au at be br bg ca cn co cu cz eg fr de gr hk hu in id ie il it jp lv lt my mx ma nl nz ng no ph pl pt ro ru sa rs sg sk si za kr se ch tw th tr ae ua gb us ve].freeze
|
6
|
+
CATEGORIES = %w[business entertainment general health science sports technology].freeze
|
7
|
+
|
8
|
+
def initialize(api_key, args:, format:, endpoint: nil)
|
9
|
+
raise 'API Key is required' unless key_present?(api_key)
|
10
|
+
raise 'Invalid parameter sequence' unless query_valid?(args, endpoint)
|
11
|
+
raise 'Invalid country sent' unless country_valid?(args)
|
12
|
+
raise 'Invalid language sent' unless language_valid?(args)
|
13
|
+
raise 'Invalid date or dates sent' unless date_valid?(args)
|
14
|
+
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def query_valid?(args, endpoint = 'top-headlines')
|
21
|
+
case endpoint
|
22
|
+
when 'top-headlines'
|
23
|
+
template = %i[q country category sources page_size page]
|
24
|
+
when 'everything'
|
25
|
+
template = %i[q sources domains excludeDomains
|
26
|
+
from to language sortBy pageSize page]
|
27
|
+
when 'sources'
|
28
|
+
template = %i[category language country]
|
29
|
+
end
|
30
|
+
|
31
|
+
if endpoint == 'top-headlines' && (args.include?(:sources) && (args.include?(:country) || args.include?(:category)))
|
32
|
+
false
|
33
|
+
elsif (endpoint == 'sources') && args.key?(:category) && (CATEGORIES.include?(args[:category]) == false)
|
34
|
+
false
|
35
|
+
else
|
36
|
+
(args.keys - template).empty?
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def country_valid?(args)
|
41
|
+
args[:country].nil? ? true : COUNTRIES.include?(args[:country].downcase)
|
42
|
+
end
|
43
|
+
|
44
|
+
def category_valid?(args)
|
45
|
+
template = %w[business entertainment general health science sports technology]
|
46
|
+
template.include?(args[:country])
|
47
|
+
end
|
48
|
+
|
49
|
+
def date_valid?(args)
|
50
|
+
if args[:from].nil? && args[:to].nil?
|
51
|
+
true
|
52
|
+
elsif args[:from] && args[:to]
|
53
|
+
(args[:from].respond_to?(:strftime) && args['to'].respond_to?(:strftime))
|
54
|
+
elsif args[:from] && args['to'].nil?
|
55
|
+
args[:from].respond_to?(:strftime)
|
56
|
+
elsif args[:from].nil? && args['to']
|
57
|
+
args[:from].respond_to?(:strftime)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|