guardian_searcher 0.1.2 → 0.1.3
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 +1 -0
- data/CHANGELOG.md +13 -0
- data/README.md +75 -1
- data/guardian_searcher.gemspec +5 -1
- data/lib/guardian_searcher/base.rb +39 -9
- data/lib/guardian_searcher/content.rb +17 -1
- data/lib/guardian_searcher/helpers/generator.rb +19 -0
- data/lib/guardian_searcher/helpers/util.rb +24 -0
- data/lib/guardian_searcher/options.rb +0 -3
- data/lib/guardian_searcher/version.rb +1 -1
- data/lib/guardian_searcher.rb +5 -0
- metadata +22 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dd89428bf856036e8d19111810e1a8b0bab64c545db11b6b0779b1f7c7654016
|
4
|
+
data.tar.gz: f485ddd884db4a21c9f75a0961640f46143014cbb392ac7de6e894726964cbce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d67c795dca8079a6768b8ab9bfd44335fde907c110dac3a4fbd3be20cab9da5e0f2ebf125f41003c936b8d13bc486ce33eae3c0e1232f3bfd6b9cd66229ead45
|
7
|
+
data.tar.gz: 4868618271ecc78d2cfc66c1389bba17504072755a06dbdd563cfa5023450ad0bc5674f09416ca728e915c46f931a65c04a912577c84f4e80035f9a899293943
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
|
3
4
|
## [0.1.0] - 2022-10-01
|
4
5
|
|
5
6
|
- Initial release
|
@@ -7,3 +8,15 @@
|
|
7
8
|
## [0.1.1] - 2022-10-01
|
8
9
|
|
9
10
|
- Fix dependency warnings
|
11
|
+
|
12
|
+
## [0.1.2] - 2022-10-04
|
13
|
+
|
14
|
+
- Moved options parse in their Options class
|
15
|
+
- Updated readme
|
16
|
+
|
17
|
+
## [0.1.3] - 2022-10-23
|
18
|
+
|
19
|
+
- Added Content class
|
20
|
+
- Added Helpers classes ( Generator & Util)
|
21
|
+
- Added some additional methods to Base class - search tags and editons endpoints
|
22
|
+
- Improved code coverage (Happy Paths only for now)
|
data/README.md
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
# GuardianSearcher
|
2
2
|
|
3
|
-
|
3
|
+
|
4
|
+
This is a work in progress, and its status is currently an alpha version. Tests needs to be implemented and the code is not optimal.
|
4
5
|
The goal of this project is to provide a Ruby wrapper to query the Guardian Api and to experiment with some programming techniques.
|
5
6
|
|
7
|
+
Documentation of TheGuardian API is [Here](https://open-platform.theguardian.com/documentation/)
|
8
|
+
|
6
9
|
If you wanna try it you need to have an API key and use it as an environment variable.
|
7
10
|
|
8
11
|
```bash
|
@@ -57,6 +60,77 @@ results = searcher.search('your keyword', { from_date: '2022-10-01', page_size:
|
|
57
60
|
|
58
61
|
If you add something unsupported it will throw an `OptionsNotSupportedError`
|
59
62
|
|
63
|
+
The results of the search can be used as they are, a Farady response object or you can parse them using `GuardianSearcher::SearchResult` in the following way:
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
response_body = searcher.search('your keyword', { from_date: '2022-10-01', page_size: 10 }).body
|
67
|
+
results = GuardianSearcher::SearchResult.parse_results(body: response_body)
|
68
|
+
```
|
69
|
+
This will return a `SearchResult` object which the following attributes:
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
@current_page
|
73
|
+
@results # an array with all the search results
|
74
|
+
@page_size # paging size
|
75
|
+
@pages # number of pages
|
76
|
+
@start # starting page
|
77
|
+
```
|
78
|
+
|
79
|
+
Of interest the structure of a single element of the results array, which is an Hash array similar to this
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
{"id"=>"football/2022/sep/23/player-mutiny-exposes-deeper-issues-within-spanish-womens-football",
|
83
|
+
"type"=>"article",
|
84
|
+
"sectionId"=>"football",
|
85
|
+
"sectionName"=>"Football",
|
86
|
+
"webPublicationDate"=>"2022-09-23T19:20:09Z",
|
87
|
+
"webTitle"=>"Player mutiny exposes deeper issues within Spanish women’s football | Sid Lowe",
|
88
|
+
"webUrl"=>"https://www.theguardian.com/football/2022/sep/23/player-mutiny-exposes-deeper-issues-within-spanish-womens-football",
|
89
|
+
"apiUrl"=>"https://content.guardianapis.com/football/2022/sep/23/player-mutiny-exposes-deeper-issues-within-spanish-womens-football",
|
90
|
+
"isHosted"=>false,
|
91
|
+
"pillarId"=>"pillar/sport",
|
92
|
+
"pillarName"=>"Sport"}
|
93
|
+
```
|
94
|
+
At this point you can use the `SearchResult` object as it is or you could convert it to an Array of `Content` objects in the following way:
|
95
|
+
```ruby
|
96
|
+
generator = GuardianSearcher::Helpers::Generator.new
|
97
|
+
# results is the SearchResult object created before which has an attribute
|
98
|
+
# called results. Not a great name choice but sorry about that
|
99
|
+
contents = generator.generate(results.results, "GuardianSearcher::Content")
|
100
|
+
```
|
101
|
+
|
102
|
+
Each element of the `contents` Array will be an instance of the `Content` class, with a number of attributes that depends on the returned results i.e. that
|
103
|
+
if an element of the results attribute is something like:
|
104
|
+
```ruby
|
105
|
+
{"id"=>"football/2022/jun/27/football-transfer-rumours-chelsea-to-sign-matthijs-de-ligt-from-juventus",
|
106
|
+
"type"=>"article",
|
107
|
+
"sectionId"=>"football",
|
108
|
+
"sectionName"=>"Football",
|
109
|
+
"webPublicationDate"=>"2022-06-27T08:42:20Z",
|
110
|
+
"webTitle"=>"Football transfer rumours: Chelsea to sign Matthijs de Ligt from Juventus? ",
|
111
|
+
"webUrl"=>"https://www.theguardian.com/football/2022/jun/27/football-transfer-rumours-chelsea-to-sign-matthijs-de-ligt-from-juventus",
|
112
|
+
"apiUrl"=>"https://content.guardianapis.com/football/2022/jun/27/football-transfer-rumours-chelsea-to-sign-matthijs-de-ligt-from-juventus",
|
113
|
+
"isHosted"=>false,
|
114
|
+
"pillarId"=>"pillar/sport",
|
115
|
+
"pillarName"=>"Sport"}
|
116
|
+
```
|
117
|
+
One element of the `contents` array will be something like:
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
<GuardianSearcher::Content:0x0000000150b7fe70
|
121
|
+
@api_url="https://content.guardianapis.com/football/2022/jun/27/football-transfer-rumours-chelsea-to-sign-matthijs-de-ligt-from-juventus",
|
122
|
+
@id="football/2022/jun/27/football-transfer-rumours-chelsea-to-sign-matthijs-de-ligt-from-juventus",
|
123
|
+
@is_hosted=false,
|
124
|
+
@pillar_id="pillar/sport",
|
125
|
+
@pillar_name="Sport",
|
126
|
+
@section_id="football",
|
127
|
+
@section_name="Football",
|
128
|
+
@type="article",
|
129
|
+
@web_publication_date="2022-06-27T08:42:20Z",
|
130
|
+
@web_title="Football transfer rumours: Chelsea to sign Matthijs de Ligt from Juventus? ",
|
131
|
+
@web_url="https://www.theguardian.com/football/2022/jun/27/football-transfer-rumours-chelsea-to-sign-matthijs-de-ligt-from-juventus">
|
132
|
+
```
|
133
|
+
|
60
134
|
## Development
|
61
135
|
|
62
136
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/guardian_searcher.gemspec
CHANGED
@@ -8,7 +8,10 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.authors = "Alain Mauri"
|
9
9
|
spec.email = "wildeng@hotmail.com"
|
10
10
|
|
11
|
-
spec.summary = "A wrapper to search articles from The Guardian
|
11
|
+
spec.summary = "A wrapper to search articles from The Guardian, using its open API.
|
12
|
+
You need to register and get your api key to properly use this gem.
|
13
|
+
It uses Faraday to make the API calls and has some classes that should help in formatting
|
14
|
+
the results as easy to manage Ruby object."
|
12
15
|
spec.homepage = "https://alainmauri.eu"
|
13
16
|
spec.license = "MIT"
|
14
17
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
|
@@ -30,6 +33,7 @@ Gem::Specification.new do |spec|
|
|
30
33
|
# spec.add_dependency "example-gem", "~> 1.0"
|
31
34
|
spec.add_dependency "faraday", "~> 2.2"
|
32
35
|
|
36
|
+
spec.add_development_dependency "byebug", "~> 11"
|
33
37
|
spec.add_development_dependency "guard", "~> 2.18"
|
34
38
|
spec.add_development_dependency "guard-bundler", "~> 3.0"
|
35
39
|
spec.add_development_dependency "guard-rspec", "~> 4.7"
|
@@ -1,36 +1,66 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module GuardianSearcher
|
4
|
+
# Class that handles the basic functionality for the Guardian Reader gem
|
4
5
|
class Base
|
5
6
|
include Faraday
|
6
7
|
|
7
8
|
attr_reader :api_key
|
8
|
-
attr_accessor :base_uri
|
9
9
|
|
10
10
|
def initialize(api_key: nil)
|
11
|
-
@base_uri = "https://content.guardianapis.com"
|
12
|
-
|
13
11
|
raise GuardianApyKeyError unless api_key
|
14
12
|
|
15
13
|
@api_key = api_key
|
16
14
|
end
|
17
15
|
|
18
16
|
# Options needs to be passed following Guardian API docs
|
19
|
-
def search(
|
20
|
-
|
17
|
+
def search(query, options = {})
|
18
|
+
url = search_uri + query_string(query, options)
|
19
|
+
Faraday.get(url)
|
20
|
+
end
|
21
21
|
|
22
|
-
|
22
|
+
def search_sections(query, options = {})
|
23
|
+
url = sections_uri + query_string(query, options)
|
23
24
|
Faraday.get(url)
|
24
25
|
end
|
25
26
|
|
26
|
-
def
|
27
|
-
|
28
|
-
url
|
27
|
+
def search_tags(query, options = {})
|
28
|
+
url = tags_uri + query_string(query, options)
|
29
|
+
Faraday.get(url)
|
30
|
+
end
|
31
|
+
|
32
|
+
def search_editions(query, options = {})
|
33
|
+
url = editions_uri + query_string(query, options)
|
29
34
|
Faraday.get(url)
|
30
35
|
end
|
31
36
|
|
32
37
|
private
|
33
38
|
|
39
|
+
def base_uri
|
40
|
+
"https://content.guardianapis.com"
|
41
|
+
end
|
42
|
+
|
43
|
+
def sections_uri
|
44
|
+
"#{base_uri}/sections"
|
45
|
+
end
|
46
|
+
|
47
|
+
def search_uri
|
48
|
+
"#{base_uri}/search"
|
49
|
+
end
|
50
|
+
|
51
|
+
def tags_uri
|
52
|
+
"#{base_uri}/tags"
|
53
|
+
end
|
54
|
+
|
55
|
+
def editions_uri
|
56
|
+
"#{base_uri}/editions"
|
57
|
+
end
|
58
|
+
|
59
|
+
def query_string(q, options = {})
|
60
|
+
opt = build_options(options)
|
61
|
+
"?q=#{q}&#{opt}&api-key=#{@api_key}"
|
62
|
+
end
|
63
|
+
|
34
64
|
def build_options(options)
|
35
65
|
Options.new(options).build_options
|
36
66
|
end
|
@@ -1,6 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module GuardianSearcher
|
4
|
-
class Content
|
4
|
+
class Content
|
5
|
+
include GuardianSearcher::Helpers::Util
|
6
|
+
def initialize(attributes)
|
7
|
+
attributes.each do |key, attribute_value|
|
8
|
+
attr_name = key
|
9
|
+
attr_name = snakecase(key) unless key.is_a? Symbol
|
10
|
+
self.class.send(:define_method, "#{attr_name}=".to_sym) do |value|
|
11
|
+
instance_variable_set("@#{attr_name}", value)
|
12
|
+
end
|
13
|
+
|
14
|
+
self.class.send(:define_method, attr_name.to_sym) do
|
15
|
+
instance_variable_get("@#{attr_name}")
|
16
|
+
end
|
17
|
+
|
18
|
+
send("#{attr_name}=".to_sym, attribute_value)
|
19
|
+
end
|
20
|
+
end
|
5
21
|
end
|
6
22
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GuardianSearcher
|
4
|
+
module Helpers
|
5
|
+
# The class helps generating an array of object from the passed parameters
|
6
|
+
# It can be used to generate e.g. an array of Content objects, each one
|
7
|
+
# initialised with the data of a single results Hash coming from the Guardian
|
8
|
+
# API response
|
9
|
+
class Generator
|
10
|
+
def generate(results, klass)
|
11
|
+
content = []
|
12
|
+
results.each do |result|
|
13
|
+
content << Object.const_get(klass).new(result)
|
14
|
+
end
|
15
|
+
content
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GuardianSearcher
|
4
|
+
module Helpers
|
5
|
+
module Util
|
6
|
+
# this method comes from the facets library
|
7
|
+
# I took it from there because it was easier for
|
8
|
+
# what I have in mind
|
9
|
+
#
|
10
|
+
# original here https://github.com/rubyworks/facets
|
11
|
+
# docs here https://www.rubydoc.info/github/rubyworks/facets/String:snakecase
|
12
|
+
def snakecase(key)
|
13
|
+
return unless key.is_a? String
|
14
|
+
|
15
|
+
key.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
16
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
17
|
+
.tr("-", "_")
|
18
|
+
.gsub(/\s/, "_")
|
19
|
+
.gsub(/__+/, "_")
|
20
|
+
.downcase
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/guardian_searcher.rb
CHANGED
@@ -3,6 +3,9 @@
|
|
3
3
|
require_relative "guardian_searcher/version"
|
4
4
|
require "faraday"
|
5
5
|
require_relative "guardian_searcher/base"
|
6
|
+
require_relative "guardian_searcher/helpers/util"
|
7
|
+
require_relative "guardian_searcher/helpers/generator"
|
8
|
+
require_relative "guardian_searcher/content"
|
6
9
|
require_relative "guardian_searcher/search"
|
7
10
|
require_relative "guardian_searcher/search_result"
|
8
11
|
require_relative "guardian_searcher/section_result"
|
@@ -11,4 +14,6 @@ require_relative "guardian_searcher/options"
|
|
11
14
|
module GuardianSearcher
|
12
15
|
class Error < StandardError; end
|
13
16
|
class GuardianApyKeyError < StandardError; end
|
17
|
+
class OptionsNotHashError < StandardError; end
|
18
|
+
class OptionsNotSupportedError < StandardError; end
|
14
19
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: guardian_searcher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alain Mauri
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-10-
|
11
|
+
date: 2022-10-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '2.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: byebug
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '11'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '11'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: guard
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -117,6 +131,8 @@ files:
|
|
117
131
|
- lib/guardian_searcher.rb
|
118
132
|
- lib/guardian_searcher/base.rb
|
119
133
|
- lib/guardian_searcher/content.rb
|
134
|
+
- lib/guardian_searcher/helpers/generator.rb
|
135
|
+
- lib/guardian_searcher/helpers/util.rb
|
120
136
|
- lib/guardian_searcher/options.rb
|
121
137
|
- lib/guardian_searcher/search.rb
|
122
138
|
- lib/guardian_searcher/search_result.rb
|
@@ -147,5 +163,8 @@ requirements: []
|
|
147
163
|
rubygems_version: 3.2.15
|
148
164
|
signing_key:
|
149
165
|
specification_version: 4
|
150
|
-
summary: A wrapper to search articles from The Guardian
|
166
|
+
summary: A wrapper to search articles from The Guardian, using its open API. You need
|
167
|
+
to register and get your api key to properly use this gem. It uses Faraday to make
|
168
|
+
the API calls and has some classes that should help in formatting the results as
|
169
|
+
easy to manage Ruby object.
|
151
170
|
test_files: []
|