metal_archives 0.8.0 → 1.0.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 +4 -4
- data/.gitignore +59 -7
- data/.rspec +1 -0
- data/.rubocop.yml +14 -0
- data/.travis.yml +11 -0
- data/Gemfile +2 -0
- data/{LICENSE → LICENSE.md} +0 -0
- data/README.md +77 -9
- data/Rakefile +5 -3
- data/lib/metal_archives.rb +8 -0
- data/lib/metal_archives/configuration.rb +28 -7
- data/lib/metal_archives/error.rb +37 -30
- data/lib/metal_archives/http_client.rb +21 -42
- data/lib/metal_archives/middleware/headers.rb +38 -0
- data/lib/metal_archives/middleware/rewrite_endpoint.rb +38 -0
- data/lib/metal_archives/models/artist.rb +51 -65
- data/lib/metal_archives/models/band.rb +41 -39
- data/lib/metal_archives/models/base_model.rb +88 -59
- data/lib/metal_archives/models/label.rb +7 -6
- data/lib/metal_archives/parsers/artist.rb +110 -99
- data/lib/metal_archives/parsers/band.rb +168 -156
- data/lib/metal_archives/parsers/label.rb +54 -52
- data/lib/metal_archives/parsers/parser.rb +73 -71
- data/lib/metal_archives/utils/collection.rb +7 -1
- data/lib/metal_archives/utils/lru_cache.rb +11 -4
- data/lib/metal_archives/utils/nil_date.rb +54 -0
- data/lib/metal_archives/utils/range.rb +16 -8
- data/lib/metal_archives/version.rb +3 -1
- data/metal_archives.gemspec +21 -11
- data/spec/configuration_spec.rb +101 -0
- data/spec/factories/artist_factory.rb +37 -0
- data/spec/factories/band_factory.rb +60 -0
- data/spec/factories/nil_date_factory.rb +9 -0
- data/spec/factories/range_factory.rb +8 -0
- data/spec/models/artist_spec.rb +142 -0
- data/spec/models/band_spec.rb +179 -0
- data/spec/models/base_model_spec.rb +217 -0
- data/spec/parser_spec.rb +19 -0
- data/spec/spec_helper.rb +111 -0
- data/spec/support/factory_girl.rb +5 -0
- data/spec/support/metal_archives.rb +26 -0
- data/spec/utils/collection_spec.rb +72 -0
- data/spec/utils/lru_cache_spec.rb +53 -0
- data/spec/utils/nil_date_spec.rb +98 -0
- data/spec/utils/range_spec.rb +62 -0
- metadata +142 -57
- data/test/base_model_test.rb +0 -111
- data/test/configuration_test.rb +0 -57
- data/test/parser_test.rb +0 -37
- data/test/property/artist_property_test.rb +0 -43
- data/test/property/band_property_test.rb +0 -94
- data/test/query/artist_query_test.rb +0 -109
- data/test/query/band_query_test.rb +0 -152
- data/test/test_helper.rb +0 -25
- data/test/utils/collection_test.rb +0 -51
- data/test/utils/lru_cache_test.rb +0 -22
- data/test/utils/range_test.rb +0 -42
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'faraday'
|
4
|
+
|
5
|
+
module MetalArchives
|
6
|
+
module Middleware
|
7
|
+
##
|
8
|
+
# Add appropriate request headers
|
9
|
+
#
|
10
|
+
class Headers < Faraday::Middleware # :nodoc:
|
11
|
+
def call(env)
|
12
|
+
headers = {
|
13
|
+
'User-Agent' => user_agent_string,
|
14
|
+
'Via' => via_string,
|
15
|
+
'Accept' => accept_string
|
16
|
+
}
|
17
|
+
|
18
|
+
env[:request_headers].merge! headers
|
19
|
+
|
20
|
+
@app.call env
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def user_agent_string
|
26
|
+
"#{MetalArchives.config.app_name}/#{MetalArchives.config.app_version} ( #{MetalArchives.config.app_contact} )"
|
27
|
+
end
|
28
|
+
|
29
|
+
def accept_string
|
30
|
+
'application/json'
|
31
|
+
end
|
32
|
+
|
33
|
+
def via_string
|
34
|
+
"gem metal_archives/#{VERSION}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'faraday'
|
4
|
+
|
5
|
+
module MetalArchives
|
6
|
+
module Middleware
|
7
|
+
##
|
8
|
+
# Dynamically rewrite endpoints
|
9
|
+
#
|
10
|
+
class RewriteEndpoint < Faraday::Middleware
|
11
|
+
def call(env)
|
12
|
+
RewriteEndpoint.rewrite(env[:url])
|
13
|
+
|
14
|
+
@app.call env
|
15
|
+
end
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def rewrite(uri)
|
19
|
+
return uri unless MetalArchives.config.endpoint
|
20
|
+
|
21
|
+
new_uri = uri.clone
|
22
|
+
|
23
|
+
default_uri = URI MetalArchives.config.default_endpoint
|
24
|
+
rewritten_uri = URI MetalArchives.config.endpoint
|
25
|
+
|
26
|
+
if uri.host == default_uri.host && uri.scheme == default_uri.scheme
|
27
|
+
new_uri.host = rewritten_uri.host
|
28
|
+
new_uri.scheme = rewritten_uri.scheme
|
29
|
+
|
30
|
+
MetalArchives.config.logger.debug "Rewrite #{uri.to_s} to #{new_uri}"
|
31
|
+
end
|
32
|
+
|
33
|
+
new_uri
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -1,8 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'date'
|
2
4
|
require 'countries'
|
3
5
|
|
4
6
|
module MetalArchives
|
5
|
-
|
6
7
|
##
|
7
8
|
# Represents a single performer (but not a solo artist)
|
8
9
|
#
|
@@ -100,7 +101,7 @@ module MetalArchives
|
|
100
101
|
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
101
102
|
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
102
103
|
#
|
103
|
-
enum :gender, :values => [
|
104
|
+
enum :gender, :values => %i[male female]
|
104
105
|
|
105
106
|
##
|
106
107
|
# :attr_reader: biography
|
@@ -124,6 +125,17 @@ module MetalArchives
|
|
124
125
|
#
|
125
126
|
property :trivia
|
126
127
|
|
128
|
+
##
|
129
|
+
# :attr_reader: photo
|
130
|
+
#
|
131
|
+
# Returns +URI+ (rewritten if config option was enabled)
|
132
|
+
#
|
133
|
+
# [Raises]
|
134
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
135
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
136
|
+
#
|
137
|
+
property :photo
|
138
|
+
|
127
139
|
##
|
128
140
|
# :attr_reader: links
|
129
141
|
#
|
@@ -146,40 +158,41 @@ module MetalArchives
|
|
146
158
|
# TODO: misc bands/albums
|
147
159
|
|
148
160
|
protected
|
149
|
-
##
|
150
|
-
# Fetch the data and assemble the model
|
151
|
-
#
|
152
|
-
# [Raises]
|
153
|
-
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
154
|
-
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
155
|
-
#
|
156
|
-
def assemble # :nodoc:
|
157
|
-
## Base attributes
|
158
|
-
url = "#{MetalArchives.config.endpoint}artist/view/id/#{id}"
|
159
|
-
response = HTTPClient.get url
|
160
161
|
|
161
|
-
|
162
|
+
##
|
163
|
+
# Fetch the data and assemble the model
|
164
|
+
#
|
165
|
+
# [Raises]
|
166
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
167
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
168
|
+
#
|
169
|
+
def assemble # :nodoc:
|
170
|
+
## Base attributes
|
171
|
+
url = "#{MetalArchives.config.default_endpoint}artist/view/id/#{id}"
|
172
|
+
response = HTTPClient.get url
|
173
|
+
|
174
|
+
properties = Parsers::Artist.parse_html response.body
|
162
175
|
|
163
|
-
|
164
|
-
|
165
|
-
|
176
|
+
## Biography
|
177
|
+
url = "#{MetalArchives.config.default_endpoint}artist/read-more/id/#{id}/field/biography"
|
178
|
+
response = HTTPClient.get url
|
166
179
|
|
167
|
-
|
180
|
+
properties[:biography] = response.body
|
168
181
|
|
169
|
-
|
170
|
-
|
171
|
-
|
182
|
+
## Trivia
|
183
|
+
url = "#{MetalArchives.config.default_endpoint}artist/read-more/id/#{id}/field/trivia"
|
184
|
+
response = HTTPClient.get url
|
172
185
|
|
173
|
-
|
186
|
+
properties[:trivia] = response.body
|
174
187
|
|
175
|
-
|
176
|
-
|
177
|
-
|
188
|
+
## Related links
|
189
|
+
url = "#{MetalArchives.config.default_endpoint}link/ajax-list/type/person/id/#{id}"
|
190
|
+
response = HTTPClient.get url
|
178
191
|
|
179
|
-
|
192
|
+
properties[:links] = Parsers::Artist.parse_links_html response.body
|
180
193
|
|
181
|
-
|
182
|
-
|
194
|
+
properties
|
195
|
+
end
|
183
196
|
|
184
197
|
class << self
|
185
198
|
##
|
@@ -191,9 +204,9 @@ module MetalArchives
|
|
191
204
|
# +Integer+
|
192
205
|
#
|
193
206
|
def find(id)
|
194
|
-
cache[id]
|
207
|
+
return cache[id] if cache.include? id
|
195
208
|
|
196
|
-
|
209
|
+
Artist.new :id => id
|
197
210
|
end
|
198
211
|
|
199
212
|
##
|
@@ -211,7 +224,7 @@ module MetalArchives
|
|
211
224
|
#
|
212
225
|
def find!(id)
|
213
226
|
obj = find id
|
214
|
-
obj
|
227
|
+
obj&.load!
|
215
228
|
|
216
229
|
obj
|
217
230
|
end
|
@@ -233,7 +246,7 @@ module MetalArchives
|
|
233
246
|
def find_by(query)
|
234
247
|
raise MetalArchives::Errors::ArgumentError unless query.include? :name
|
235
248
|
|
236
|
-
url = "#{MetalArchives.config.
|
249
|
+
url = "#{MetalArchives.config.default_endpoint}search/ajax-artist-search/"
|
237
250
|
params = Parsers::Artist.map_params query
|
238
251
|
|
239
252
|
response = HTTPClient.get url, params
|
@@ -242,7 +255,7 @@ module MetalArchives
|
|
242
255
|
return nil if json['aaData'].empty?
|
243
256
|
|
244
257
|
data = json['aaData'].first
|
245
|
-
id = Nokogiri::HTML(data.first).xpath('//a/@href').first.value.
|
258
|
+
id = Nokogiri::HTML(data.first).xpath('//a/@href').first.value.delete('\\').split('/').last.gsub(/\D/, '').to_i
|
246
259
|
|
247
260
|
find id
|
248
261
|
end
|
@@ -264,7 +277,7 @@ module MetalArchives
|
|
264
277
|
#
|
265
278
|
def find_by!(query)
|
266
279
|
obj = find_by query
|
267
|
-
obj
|
280
|
+
obj&.load!
|
268
281
|
|
269
282
|
obj
|
270
283
|
end
|
@@ -285,7 +298,7 @@ module MetalArchives
|
|
285
298
|
def search(name)
|
286
299
|
raise MetalArchives::Errors::ArgumentError unless name.is_a? String
|
287
300
|
|
288
|
-
url = "#{MetalArchives.config.
|
301
|
+
url = "#{MetalArchives.config.default_endpoint}search/ajax-artist-search/"
|
289
302
|
query = { :name => name }
|
290
303
|
|
291
304
|
params = Parsers::Artist.map_params query
|
@@ -293,7 +306,7 @@ module MetalArchives
|
|
293
306
|
l = lambda do
|
294
307
|
@start ||= 0
|
295
308
|
|
296
|
-
if @max_items
|
309
|
+
if @max_items && @start >= @max_items
|
297
310
|
[]
|
298
311
|
else
|
299
312
|
response = HTTPClient.get url, params.merge(:iDisplayStart => @start)
|
@@ -305,7 +318,7 @@ module MetalArchives
|
|
305
318
|
|
306
319
|
json['aaData'].each do |data|
|
307
320
|
# Create Artist object for every ID in the results list
|
308
|
-
id = Nokogiri::HTML(data.first).xpath('//a/@href').first.value.
|
321
|
+
id = Nokogiri::HTML(data.first).xpath('//a/@href').first.value.delete('\\').split('/').last.gsub(/\D/, '').to_i
|
309
322
|
objects << Artist.find(id)
|
310
323
|
end
|
311
324
|
|
@@ -328,34 +341,7 @@ module MetalArchives
|
|
328
341
|
# - rdoc-ref:MetalArchives::Errors::ParserError when parsing failed. Please report this error.
|
329
342
|
#
|
330
343
|
def all
|
331
|
-
|
332
|
-
|
333
|
-
l = lambda do
|
334
|
-
@start ||= 0
|
335
|
-
|
336
|
-
if @max_items and @start >= @max_items
|
337
|
-
[]
|
338
|
-
else
|
339
|
-
response = HTTPClient.get url, :iDisplayStart => @start
|
340
|
-
json = JSON.parse response.body
|
341
|
-
|
342
|
-
@max_items = json['iTotalRecords']
|
343
|
-
|
344
|
-
objects = []
|
345
|
-
|
346
|
-
json['aaData'].each do |data|
|
347
|
-
# Create Artist object for every ID in the results list
|
348
|
-
id = Nokogiri::HTML(data.first).xpath('//a/@href').first.value.gsub('\\', '').split('/').last.gsub(/\D/, '').to_i
|
349
|
-
objects << Artist.find(id)
|
350
|
-
end
|
351
|
-
|
352
|
-
@start += 200
|
353
|
-
|
354
|
-
objects
|
355
|
-
end
|
356
|
-
end
|
357
|
-
|
358
|
-
MetalArchives::Collection.new l
|
344
|
+
search ''
|
359
345
|
end
|
360
346
|
end
|
361
347
|
end
|
@@ -1,8 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'date'
|
2
4
|
require 'countries'
|
3
5
|
|
4
6
|
module MetalArchives
|
5
|
-
|
6
7
|
##
|
7
8
|
# Represents an band (person or group)
|
8
9
|
#
|
@@ -144,7 +145,7 @@ module MetalArchives
|
|
144
145
|
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
145
146
|
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
146
147
|
#
|
147
|
-
enum :status, :values => [
|
148
|
+
enum :status, :values => %i[active split_up on_hold unknown changed_name disputed]
|
148
149
|
|
149
150
|
# TODO: releases
|
150
151
|
# TODO: members
|
@@ -167,7 +168,7 @@ module MetalArchives
|
|
167
168
|
##
|
168
169
|
# :attr_reader: logo
|
169
170
|
#
|
170
|
-
# Returns +
|
171
|
+
# Returns +URI+ (rewritten if config option was enabled)
|
171
172
|
#
|
172
173
|
# [Raises]
|
173
174
|
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
@@ -178,7 +179,7 @@ module MetalArchives
|
|
178
179
|
##
|
179
180
|
# :attr_reader: photo
|
180
181
|
#
|
181
|
-
# Returns +
|
182
|
+
# Returns +URI+ (rewritten if config option was enabled)
|
182
183
|
#
|
183
184
|
# [Raises]
|
184
185
|
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
@@ -203,40 +204,41 @@ module MetalArchives
|
|
203
204
|
property :links, :multiple => true
|
204
205
|
|
205
206
|
protected
|
206
|
-
##
|
207
|
-
# Fetch the data and assemble the model
|
208
|
-
#
|
209
|
-
# [Raises]
|
210
|
-
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when receiving a status code == 404
|
211
|
-
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
212
|
-
#
|
213
|
-
def assemble # :nodoc:
|
214
|
-
## Base attributes
|
215
|
-
url = "#{MetalArchives.config.endpoint}band/view/id/#{id}"
|
216
|
-
response = HTTPClient.get url
|
217
207
|
|
218
|
-
|
208
|
+
##
|
209
|
+
# Fetch the data and assemble the model
|
210
|
+
#
|
211
|
+
# [Raises]
|
212
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when receiving a status code == 404
|
213
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
214
|
+
#
|
215
|
+
def assemble # :nodoc:
|
216
|
+
## Base attributes
|
217
|
+
url = "#{MetalArchives.config.default_endpoint}band/view/id/#{id}"
|
218
|
+
response = HTTPClient.get url
|
219
219
|
|
220
|
-
|
221
|
-
url = "#{MetalArchives.config.endpoint}band/read-more/id/#{id}"
|
222
|
-
response = HTTPClient.get url
|
220
|
+
properties = Parsers::Band.parse_html response.body
|
223
221
|
|
224
|
-
|
222
|
+
## Comment
|
223
|
+
url = "#{MetalArchives.config.default_endpoint}band/read-more/id/#{id}"
|
224
|
+
response = HTTPClient.get url
|
225
225
|
|
226
|
-
|
227
|
-
url = "#{MetalArchives.config.endpoint}band/ajax-recommendations/id/#{id}"
|
228
|
-
response = HTTPClient.get url
|
226
|
+
properties[:comment] = response.body
|
229
227
|
|
230
|
-
|
228
|
+
## Similar artists
|
229
|
+
url = "#{MetalArchives.config.default_endpoint}band/ajax-recommendations/id/#{id}"
|
230
|
+
response = HTTPClient.get url
|
231
231
|
|
232
|
-
|
233
|
-
url = "#{MetalArchives.config.endpoint}link/ajax-list/type/band/id/#{id}"
|
234
|
-
response = HTTPClient.get url
|
232
|
+
properties[:similar] = Parsers::Band.parse_similar_bands_html response.body
|
235
233
|
|
236
|
-
|
234
|
+
## Related links
|
235
|
+
url = "#{MetalArchives.config.default_endpoint}link/ajax-list/type/band/id/#{id}"
|
236
|
+
response = HTTPClient.get url
|
237
237
|
|
238
|
-
|
239
|
-
|
238
|
+
properties[:links] = Parsers::Band.parse_related_links_html response.body
|
239
|
+
|
240
|
+
properties
|
241
|
+
end
|
240
242
|
|
241
243
|
class << self
|
242
244
|
##
|
@@ -248,9 +250,9 @@ module MetalArchives
|
|
248
250
|
# +Integer+
|
249
251
|
#
|
250
252
|
def find(id)
|
251
|
-
cache[id]
|
253
|
+
return cache[id] if cache.include? id
|
252
254
|
|
253
|
-
|
255
|
+
Band.new :id => id
|
254
256
|
end
|
255
257
|
|
256
258
|
##
|
@@ -299,7 +301,7 @@ module MetalArchives
|
|
299
301
|
# - +:independent+: boolean
|
300
302
|
#
|
301
303
|
def find_by(query)
|
302
|
-
url = "#{MetalArchives.config.
|
304
|
+
url = "#{MetalArchives.config.default_endpoint}search/ajax-advanced/searching/bands"
|
303
305
|
params = Parsers::Band.map_params query
|
304
306
|
|
305
307
|
response = HTTPClient.get url, params
|
@@ -308,7 +310,7 @@ module MetalArchives
|
|
308
310
|
return nil if json['aaData'].empty?
|
309
311
|
|
310
312
|
data = json['aaData'].first
|
311
|
-
id = Nokogiri::HTML(data.first).xpath('//a/@href').first.value.
|
313
|
+
id = Nokogiri::HTML(data.first).xpath('//a/@href').first.value.delete('\\').split('/').last.gsub(/\D/, '').to_i
|
312
314
|
|
313
315
|
find id
|
314
316
|
end
|
@@ -340,7 +342,7 @@ module MetalArchives
|
|
340
342
|
#
|
341
343
|
def find_by!(query)
|
342
344
|
obj = find_by query
|
343
|
-
obj
|
345
|
+
obj&.load!
|
344
346
|
|
345
347
|
obj
|
346
348
|
end
|
@@ -371,14 +373,14 @@ module MetalArchives
|
|
371
373
|
# - +:independent+: boolean
|
372
374
|
#
|
373
375
|
def search_by(query)
|
374
|
-
url = "#{MetalArchives.config.
|
376
|
+
url = "#{MetalArchives.config.default_endpoint}search/ajax-advanced/searching/bands"
|
375
377
|
|
376
378
|
params = Parsers::Band.map_params query
|
377
379
|
|
378
380
|
l = lambda do
|
379
381
|
@start ||= 0
|
380
382
|
|
381
|
-
if @max_items
|
383
|
+
if @max_items && @start >= @max_items
|
382
384
|
[]
|
383
385
|
else
|
384
386
|
response = HTTPClient.get url, params.merge(:iDisplayStart => @start)
|
@@ -390,7 +392,7 @@ module MetalArchives
|
|
390
392
|
|
391
393
|
json['aaData'].each do |data|
|
392
394
|
# Create Band object for every ID in the results list
|
393
|
-
id = Nokogiri::HTML(data.first).xpath('//a/@href').first.value.
|
395
|
+
id = Nokogiri::HTML(data.first).xpath('//a/@href').first.value.delete('\\').split('/').last.gsub(/\D/, '').to_i
|
394
396
|
objects << Band.find(id)
|
395
397
|
end
|
396
398
|
|
@@ -432,7 +434,7 @@ module MetalArchives
|
|
432
434
|
# - rdoc-ref:MetalArchives::Errors::ParserError when parsing failed. Please report this error.
|
433
435
|
#
|
434
436
|
def all
|
435
|
-
search_by
|
437
|
+
search_by({})
|
436
438
|
end
|
437
439
|
end
|
438
440
|
end
|