allnewsapi 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7070e32db6b43993f4a69273423bfd56170ba615f69fc6becc2b645b857bb6f6
4
+ data.tar.gz: 6981d360e096c4026881101f31692d2c16ceace106fd117258ee92aab855b2b3
5
+ SHA512:
6
+ metadata.gz: 9820688bee7fe1b2b73ae6ff49d04e6e7ba583cf9c28d31fcc4be141381b035e38eea9714d6a5d49e685eb0ee2e609b50af4ac0d8b05be127d8dfcff0f894cb4
7
+ data.tar.gz: dc62514cc552427c2aa9dc6693674a401a554b5a07a02fb936abd5a103f130a452c0e38fd165ed8f1dfdb817bee57426626aa7a5149de40672486a02fa147573
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 AllNewsAPI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,110 @@
1
+ # AllNewsAPI Ruby SDK
2
+
3
+ [![Gem](https://img.shields.io/gem/v/allnewsapi)](https://rubygems.org/gems/allnewsapi)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ A lightweight Ruby SDK for the [AllNewsAPI](https://allnewsapi.com) with zero external dependencies. Uses `net/http` only.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ gem install allnewsapi
12
+ ```
13
+
14
+ Or add to your Gemfile:
15
+
16
+ ```ruby
17
+ gem 'allnewsapi'
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ ```ruby
23
+ require 'allnewsapi'
24
+
25
+ client = AllNewsAPI::Client.new('your-api-key')
26
+
27
+ results = client.search(q: 'artificial intelligence', lang: 'en', max: 10)
28
+
29
+ results['articles'].each do |article|
30
+ puts "#{article['title']} — #{article['source']['name']}"
31
+ end
32
+ ```
33
+
34
+ ## Methods
35
+
36
+ ### `search(**params) -> Hash`
37
+
38
+ Search for news articles matching any combination of filters.
39
+
40
+ ```ruby
41
+ results = client.search(
42
+ q: 'climate change',
43
+ start_date: '2024-01-01',
44
+ end_date: '2024-06-01',
45
+ lang: ['en', 'fr'],
46
+ category: 'science',
47
+ max: 20
48
+ )
49
+ ```
50
+
51
+ ### `headlines(**params) -> Hash`
52
+
53
+ Fetch top headlines with the same filtering options as search.
54
+
55
+ ```ruby
56
+ headlines = client.headlines(country: 'us', category: 'business', max: 5)
57
+ ```
58
+
59
+ ### `usage -> Hash`
60
+
61
+ Check your API quota and consumption.
62
+
63
+ ```ruby
64
+ usage = client.usage
65
+ puts "Remaining: #{usage['requestsRemaining24Hours']}/#{usage['requestsLimit24Hours']}"
66
+ ```
67
+
68
+ ## Parameter Reference
69
+
70
+ | Parameter | Type | Description |
71
+ |-----------|------|-------------|
72
+ | q | `String` | Keywords to search for |
73
+ | start_date | `String \| Date` | Start date (ISO 8601) |
74
+ | end_date | `String \| Date` | End date (ISO 8601) |
75
+ | content | `Boolean` | Include full article content |
76
+ | lang | `String \| Array` | Language(s) to filter by |
77
+ | country | `String \| Array` | Country/countries to filter by |
78
+ | region | `String \| Array` | Region(s) to filter by |
79
+ | category | `String \| Array` | Category/categories to filter by |
80
+ | max | `Integer` | Maximum results (1-100) |
81
+ | attributes | `String \| Array` | Search in title/description/content |
82
+ | page | `Integer` | Page number |
83
+ | sortby | `String` | Sort by `publishedAt` or `relevance` |
84
+ | publisher | `String \| Array` | Publisher(s) to filter |
85
+ | format | `String` | Response format: `json`, `csv`, or `xlsx` |
86
+ | ai_sentiment | `String` | AI sentiment filter |
87
+ | ai_entity_name | `String` | AI entity name filter |
88
+ | ai_entity_type | `String` | AI entity type filter |
89
+
90
+ ## Error Handling
91
+
92
+ ```ruby
93
+ require 'allnewsapi'
94
+
95
+ client = AllNewsAPI::Client.new('your-api-key')
96
+
97
+ begin
98
+ results = client.search(q: 'ruby')
99
+ rescue AllNewsAPI::NewsAPIError => e
100
+ puts "Error #{e.status_code}: #{e.message}"
101
+ end
102
+ ```
103
+
104
+ ## License
105
+
106
+ MIT
107
+
108
+ ## Support
109
+
110
+ Found a bug or have a feature request? Please [open an issue](https://github.com/AllNewsAPI/sdks/issues) on GitHub.
@@ -0,0 +1,206 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'uri'
5
+ require 'json'
6
+ require 'date'
7
+
8
+ module AllNewsAPI
9
+ # Main SDK client for interacting with AllNewsAPI
10
+ class Client
11
+ # Default base URL for the AllNewsAPI
12
+ DEFAULT_BASE_URL = 'https://api.allnewsapi.com'
13
+
14
+ # Default HTTP timeout in seconds
15
+ DEFAULT_TIMEOUT = 30
16
+
17
+ # Parameters that should NOT be converted from snake_case to camelCase
18
+ AI_PARAMS = %w[ai_sentiment ai_entity_name ai_entity_type].freeze
19
+
20
+ # Create a new AllNewsAPI client
21
+ #
22
+ # @param api_key [String] Your AllNewsAPI key
23
+ # @param options [Hash] Optional configuration options
24
+ # @option options [String] :base_url The base URL for the API
25
+ # @option options [Integer] :timeout HTTP timeout in seconds (default: 30)
26
+ def initialize(api_key, options = {})
27
+ if api_key.nil? || api_key.to_s.strip.empty?
28
+ raise Error.new(401, 'Unauthorized - Invalid API Key or Account status is inactive')
29
+ end
30
+
31
+ @api_key = api_key
32
+ @base_url = options[:base_url] || DEFAULT_BASE_URL
33
+ @timeout = options[:timeout] || DEFAULT_TIMEOUT
34
+ @search_endpoint = "#{@base_url}/search"
35
+ @headlines_endpoint = "#{@base_url}/headlines"
36
+ @usage_endpoint = "#{@base_url}/usage"
37
+ end
38
+
39
+ # Search for news articles
40
+ #
41
+ # @param options [Hash] Search options
42
+ # @option options [String] :q Keywords to search for
43
+ # @option options [String, Date] :start_date Start date (YYYY-MM-DD or Date object)
44
+ # @option options [String, Date] :end_date End date (YYYY-MM-DD or Date object)
45
+ # @option options [Boolean] :content Whether to include full content
46
+ # @option options [String, Array<String>] :lang Language(s) to filter by
47
+ # @option options [String, Array<String>] :country Country/countries to filter by
48
+ # @option options [String, Array<String>] :region Region(s) to filter by
49
+ # @option options [String, Array<String>] :category Category/categories to filter by
50
+ # @option options [Integer] :max Maximum number of results (1-100)
51
+ # @option options [String, Array<String>] :attributes Attributes to search in
52
+ # @option options [Integer] :page Page number for pagination
53
+ # @option options [String] :sortby Sort by 'publishedAt' or 'relevance'
54
+ # @option options [String, Array<String>] :publisher Publisher(s) to filter by
55
+ # @option options [String] :format Response format (json, csv, xlsx)
56
+ # @option options [String] :ai_sentiment AI sentiment filter
57
+ # @option options [String] :ai_entity_name AI entity name filter
58
+ # @option options [String] :ai_entity_type AI entity type filter
59
+ #
60
+ # @return [Hash, String] Search results (Hash for JSON, String for CSV/XLSX)
61
+ def search(options = {})
62
+ params = prepare_params(options)
63
+ make_request(params, @search_endpoint)
64
+ end
65
+
66
+ # Get top headlines
67
+ #
68
+ # @param options [Hash] Headlines options (same as search)
69
+ #
70
+ # @return [Hash, String] Headlines results (Hash for JSON, String for CSV/XLSX)
71
+ def headlines(options = {})
72
+ params = prepare_params(options)
73
+ make_request(params, @headlines_endpoint)
74
+ end
75
+
76
+ # Get account usage statistics
77
+ #
78
+ # @return [Hash] Usage statistics
79
+ def usage
80
+ make_request({}, @usage_endpoint)
81
+ end
82
+
83
+ private
84
+
85
+ # Prepare parameters by converting dates to ISO 8601 format
86
+ #
87
+ # @param options [Hash] Raw options from the user
88
+ # @return [Hash] Prepared options with dates converted
89
+ def prepare_params(options)
90
+ params = options.dup
91
+ params[:start_date] = params[:start_date].iso8601 if params[:start_date].is_a?(Date)
92
+ params[:end_date] = params[:end_date].iso8601 if params[:end_date].is_a?(Date)
93
+ params
94
+ end
95
+
96
+ # Build the URL with query parameters for the API request
97
+ #
98
+ # @param params [Hash] Query parameters for the request
99
+ # @param endpoint [String] The API endpoint to use
100
+ # @return [URI] The complete URI for the API request
101
+ def build_url(params, endpoint)
102
+ uri = URI(endpoint)
103
+ query_params = []
104
+ query_params << ['apikey', @api_key]
105
+
106
+ params.each do |key, value|
107
+ next if value.nil?
108
+
109
+ # Convert parameter name
110
+ api_key_name = convert_param_name(key)
111
+
112
+ # Handle array values by joining them with commas
113
+ param_value = value.is_a?(Array) ? value.join(',') : value.to_s
114
+
115
+ query_params << [api_key_name, param_value]
116
+ end
117
+
118
+ uri.query = URI.encode_www_form(query_params)
119
+ uri
120
+ end
121
+
122
+ # Convert Ruby snake_case parameter name to API camelCase
123
+ # AI params are kept as-is since they already match the API format
124
+ #
125
+ # @param key [Symbol, String] Ruby parameter name
126
+ # @return [String] API parameter name
127
+ def convert_param_name(key)
128
+ key_str = key.to_s
129
+
130
+ # AI params stay as-is
131
+ return key_str if AI_PARAMS.include?(key_str)
132
+
133
+ # Convert snake_case to camelCase
134
+ key_str.gsub(/_([a-z])/) { ::Regexp.last_match(1).upcase }
135
+ end
136
+
137
+ # Make a request to the API
138
+ #
139
+ # @param params [Hash] Query parameters for the request
140
+ # @param endpoint [String] The API endpoint to use
141
+ # @return [Hash, String] The API response
142
+ def make_request(params, endpoint)
143
+ uri = build_url(params, endpoint)
144
+
145
+ begin
146
+ http = Net::HTTP.new(uri.host, uri.port)
147
+ http.use_ssl = (uri.scheme == 'https')
148
+ http.open_timeout = @timeout
149
+ http.read_timeout = @timeout
150
+
151
+ request = Net::HTTP::Get.new(uri)
152
+ response = http.start { |h| h.request(request) }
153
+
154
+ # Handle HTTP errors
155
+ unless response.is_a?(Net::HTTPSuccess)
156
+ error_message = parse_error_message(response)
157
+ raise Error.new(response.code.to_i, error_message)
158
+ end
159
+
160
+ # Handle different formats
161
+ format = params[:format] || 'json'
162
+
163
+ case format.to_s
164
+ when 'json'
165
+ JSON.parse(response.body)
166
+ else
167
+ response.body
168
+ end
169
+ rescue Error => e
170
+ raise e
171
+ rescue SocketError, Timeout::Error, Errno::ECONNREFUSED => e
172
+ raise Error.new(500, "Request failed: #{e.message}")
173
+ rescue StandardError => e
174
+ raise Error.new(500, "Request failed: #{e.message}")
175
+ end
176
+ end
177
+
178
+ # Parse error message from API response
179
+ #
180
+ # @param response [Net::HTTPResponse] The error response
181
+ # @return [String] The error message
182
+ def parse_error_message(response)
183
+ error_data = JSON.parse(response.body)
184
+ error_data.dig('detail', 'message') || default_error_message(response.code.to_i)
185
+ rescue JSON::ParserError, TypeError
186
+ default_error_message(response.code.to_i)
187
+ end
188
+
189
+ # Get a default error message based on status code
190
+ #
191
+ # @param status_code [Integer] HTTP status code
192
+ # @return [String] Default error message
193
+ def default_error_message(status_code)
194
+ messages = {
195
+ 400 => 'Bad Request - Your request is invalid',
196
+ 401 => 'Unauthorized - Invalid API Key or Account status is inactive',
197
+ 403 => 'Forbidden - Your account is not authorized to make that request',
198
+ 429 => 'Too Many Requests - You have reached your daily request limit',
199
+ 500 => 'Internal Server Error - We had a problem with our server',
200
+ 503 => "Service Unavailable - We're temporarily offline for maintenance"
201
+ }
202
+
203
+ messages[status_code] || 'Unknown error occurred'
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AllNewsAPI
4
+ # Custom error class for AllNewsAPI errors
5
+ class Error < StandardError
6
+ attr_reader :status_code
7
+
8
+ # @param status_code [Integer] HTTP status code
9
+ # @param message [String] Error message
10
+ def initialize(status_code, message)
11
+ @status_code = status_code
12
+ super(message)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AllNewsAPI
4
+ VERSION = '0.2.0'
5
+ end
data/lib/allnewsapi.rb ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'allnewsapi/version'
4
+ require_relative 'allnewsapi/error'
5
+ require_relative 'allnewsapi/client'
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: allnewsapi
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - AllNewsAPI
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-08-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '13.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '13.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: webmock
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.14'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.14'
69
+ description: A simple Ruby wrapper for the AllNewsAPI that allows you to search for
70
+ news articles, get headlines, and check usage statistics.
71
+ email:
72
+ - contact@allnewsapi.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - LICENSE
78
+ - README.md
79
+ - lib/allnewsapi.rb
80
+ - lib/allnewsapi/client.rb
81
+ - lib/allnewsapi/error.rb
82
+ - lib/allnewsapi/version.rb
83
+ homepage: https://github.com/AllNewsAPI/ruby-sdk
84
+ licenses:
85
+ - MIT
86
+ metadata:
87
+ homepage_uri: https://github.com/AllNewsAPI/ruby-sdk
88
+ source_code_uri: https://github.com/AllNewsAPI/ruby-sdk
89
+ changelog_uri: https://github.com/AllNewsAPI/ruby-sdk/blob/main/CHANGELOG.md
90
+ documentation_uri: https://www.rubydoc.info/gems/allnewsapi
91
+ bug_tracker_uri: https://github.com/AllNewsAPI/ruby-sdk/issues
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '3.0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubygems_version: 3.3.27
108
+ signing_key:
109
+ specification_version: 4
110
+ summary: A Ruby SDK for the AllNewsAPI
111
+ test_files: []