metal_archives 2.2.0 → 2.2.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.
Files changed (61) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ci.yml +46 -0
  3. data/.github/workflows/release.yml +69 -0
  4. data/.gitignore +6 -6
  5. data/.overcommit.yml +35 -0
  6. data/.rspec +1 -0
  7. data/.rubocop.yml +54 -8
  8. data/.rubocop_todo.yml +92 -0
  9. data/CHANGELOG.md +22 -0
  10. data/Gemfile +1 -1
  11. data/LICENSE.md +1 -1
  12. data/README.md +35 -64
  13. data/Rakefile +8 -7
  14. data/bin/console +41 -0
  15. data/bin/setup +8 -0
  16. data/docker-compose.yml +14 -0
  17. data/lib/metal_archives.rb +48 -29
  18. data/lib/metal_archives/{utils/collection.rb → collection.rb} +0 -0
  19. data/lib/metal_archives/configuration.rb +9 -33
  20. data/lib/metal_archives/{error.rb → errors.rb} +0 -0
  21. data/lib/metal_archives/http_client.rb +13 -8
  22. data/lib/metal_archives/{utils/lru_cache.rb → lru_cache.rb} +0 -0
  23. data/lib/metal_archives/middleware/cache_check.rb +2 -4
  24. data/lib/metal_archives/middleware/encoding.rb +2 -2
  25. data/lib/metal_archives/middleware/headers.rb +5 -5
  26. data/lib/metal_archives/middleware/rewrite_endpoint.rb +2 -2
  27. data/lib/metal_archives/models/artist.rb +40 -24
  28. data/lib/metal_archives/models/band.rb +47 -29
  29. data/lib/metal_archives/models/base_model.rb +64 -61
  30. data/lib/metal_archives/models/label.rb +11 -11
  31. data/lib/metal_archives/models/release.rb +17 -15
  32. data/lib/metal_archives/{utils/nil_date.rb → nil_date.rb} +10 -18
  33. data/lib/metal_archives/parsers/artist.rb +62 -31
  34. data/lib/metal_archives/parsers/band.rb +97 -74
  35. data/lib/metal_archives/parsers/label.rb +21 -21
  36. data/lib/metal_archives/parsers/parser.rb +23 -8
  37. data/lib/metal_archives/parsers/release.rb +77 -72
  38. data/lib/metal_archives/{utils/range.rb → range.rb} +5 -2
  39. data/lib/metal_archives/version.rb +12 -1
  40. data/metal_archives.env.example +7 -0
  41. data/metal_archives.gemspec +40 -28
  42. data/nginx/default.conf +60 -0
  43. metadata +126 -65
  44. data/.travis.yml +0 -12
  45. data/spec/configuration_spec.rb +0 -96
  46. data/spec/factories/artist_factory.rb +0 -37
  47. data/spec/factories/band_factory.rb +0 -60
  48. data/spec/factories/nil_date_factory.rb +0 -9
  49. data/spec/factories/range_factory.rb +0 -8
  50. data/spec/models/artist_spec.rb +0 -138
  51. data/spec/models/band_spec.rb +0 -164
  52. data/spec/models/base_model_spec.rb +0 -219
  53. data/spec/models/release_spec.rb +0 -133
  54. data/spec/parser_spec.rb +0 -19
  55. data/spec/spec_helper.rb +0 -111
  56. data/spec/support/factory_girl.rb +0 -5
  57. data/spec/support/metal_archives.rb +0 -33
  58. data/spec/utils/collection_spec.rb +0 -72
  59. data/spec/utils/lru_cache_spec.rb +0 -53
  60. data/spec/utils/nil_date_spec.rb +0 -156
  61. data/spec/utils/range_spec.rb +0 -62
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'date'
3
+ require "date"
4
+ require "nokogiri"
4
5
 
5
6
  module MetalArchives
6
7
  ##
@@ -12,7 +13,7 @@ module MetalArchives
12
13
  #
13
14
  # Returns +Integer+
14
15
  #
15
- property :id, :type => Integer
16
+ property :id, type: Integer
16
17
 
17
18
  ##
18
19
  # :attr_reader: title
@@ -36,7 +37,7 @@ module MetalArchives
36
37
  # - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
37
38
  # - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
38
39
  #
39
- enum :type, :values => %i[full_length live demo single ep video boxed_set split compilation split_video collaboration]
40
+ enum :type, values: %i(full_length live demo single ep video boxed_set split compilation split_video collaboration)
40
41
 
41
42
  ##
42
43
  # :attr_reader: date_released
@@ -47,7 +48,7 @@ module MetalArchives
47
48
  # - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
48
49
  # - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
49
50
  #
50
- property :date_released, :type => NilDate
51
+ property :date_released, type: NilDate
51
52
 
52
53
  ##
53
54
  # :attr_reader_: catalog_id
@@ -76,7 +77,7 @@ module MetalArchives
76
77
  ##
77
78
  # :attr_reader: format
78
79
  #
79
- # Returns +:cd+, +:cassette+, +:vinyl+, +:vhs+, +:dvd+, +:digital+, +:blu_ray+, +:other+
80
+ # Returns +:cd+, +:cassette+, +:vinyl+, +:vhs+, +:dvd+, +:digital+, +:blu_ray+, +:other+, +:unknown+
80
81
  #
81
82
  # [Raises]
82
83
  # - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
@@ -143,7 +144,7 @@ module MetalArchives
143
144
  def find(id)
144
145
  return cache[id] if cache.include? id
145
146
 
146
- Release.new :id => id
147
+ Release.new id: id
147
148
  end
148
149
 
149
150
  ##
@@ -205,10 +206,10 @@ module MetalArchives
205
206
  response = HTTPClient.get url, params
206
207
  json = JSON.parse response.body
207
208
 
208
- return nil if json['aaData'].empty?
209
+ return nil if json["aaData"].empty?
209
210
 
210
- data = json['aaData'].first
211
- id = Nokogiri::HTML(data[1]).xpath('//a/@href').first.value.delete('\\').split('/').last.gsub(/\D/, '').to_i
211
+ data = json["aaData"].first
212
+ id = Nokogiri::HTML(data[1]).xpath("//a/@href").first.value.delete('\\').split("/").last.gsub(/\D/, "").to_i
212
213
 
213
214
  find id
214
215
  end
@@ -295,16 +296,16 @@ module MetalArchives
295
296
  if @max_items && @start >= @max_items
296
297
  []
297
298
  else
298
- response = HTTPClient.get url, params.merge(:iDisplayStart => @start)
299
+ response = HTTPClient.get url, params.merge(iDisplayStart: @start)
299
300
  json = JSON.parse response.body
300
301
 
301
- @max_items = json['iTotalRecords']
302
+ @max_items = json["iTotalRecords"]
302
303
 
303
304
  objects = []
304
305
 
305
- json['aaData'].each do |data|
306
+ json["aaData"].each do |data|
306
307
  # Create Release object for every ID in the results list
307
- id = Nokogiri::HTML(data.first).xpath('//a/@href').first.value.delete('\\').split('/').last.gsub(/\D/, '').to_i
308
+ id = Nokogiri::HTML(data.first).xpath("//a/@href").first.value.delete('\\').split("/").last.gsub(/\D/, "").to_i
308
309
  objects << Release.find(id)
309
310
  end
310
311
 
@@ -333,7 +334,8 @@ module MetalArchives
333
334
  #
334
335
  def search(title)
335
336
  raise MetalArchives::Errors::ArgumentError unless title.is_a? String
336
- search_by :title => title
337
+
338
+ search_by title: title
337
339
  end
338
340
 
339
341
  ##
@@ -346,7 +348,7 @@ module MetalArchives
346
348
  # - rdoc-ref:MetalArchives::Errors::ParserError when parsing failed. Please report this error.
347
349
  #
348
350
  def all
349
- search ''
351
+ search ""
350
352
  end
351
353
  end
352
354
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'date'
3
+ require "date"
4
4
 
5
5
  module MetalArchives
6
6
  ##
@@ -35,7 +35,7 @@ module MetalArchives
35
35
  # Return a +Date+ object
36
36
  #
37
37
  def date
38
- raise MetalArchives::Errors::ArgumentError, "Invalid conversion to Date: #{self.to_s}" unless year?
38
+ raise MetalArchives::Errors::ArgumentError, "Invalid conversion to Date: #{self}" unless year?
39
39
 
40
40
  ::Date.new @year, month || 1, day || 1
41
41
  end
@@ -44,7 +44,7 @@ module MetalArchives
44
44
  # Parse YYYY[-MM[-DD]]
45
45
  #
46
46
  def self.parse(value)
47
- split = value.split('-')
47
+ split = value.split("-")
48
48
 
49
49
  year = Integer(split[0], 10) if split.any? && split[0] && !split[0].empty?
50
50
  year = nil if year == 0
@@ -55,19 +55,11 @@ module MetalArchives
55
55
  day = Integer(split[2], 10) if split.length > 2 && split[2] && !split[2].empty?
56
56
  day = nil if day == 0
57
57
 
58
- return MetalArchives::NilDate.new year, month, day
59
- rescue => e
58
+ MetalArchives::NilDate.new year, month, day
59
+ rescue StandardError => e
60
60
  raise MetalArchives::Errors::ArgumentError, "Invalid date: #{value}: #{e}"
61
61
  end
62
62
 
63
- def to_s
64
- year = (@year || 0).to_s.rjust 2, '0'
65
- month = (@month || 0).to_s.rjust 2, '0'
66
- day = (@day || 0).to_s.rjust 2, '0'
67
-
68
- "#{year}-#{month}-#{day}"
69
- end
70
-
71
63
  ##
72
64
  # Comparison operator
73
65
  #
@@ -75,21 +67,21 @@ module MetalArchives
75
67
  return nil if other.nil?
76
68
 
77
69
  # Return nil if one of the two years is nil
78
- return nil if (@year.nil? && !other.year.nil?) || !@year.nil? && other.year.nil?
70
+ return nil if (@year.nil? && !other.year.nil?) || (!@year.nil? && other.year.nil?)
79
71
 
80
72
  # Return nil if one of the two months is nil
81
- return nil if (@month.nil? && !other.month.nil?) || !@month.nil? && other.month.nil?
73
+ return nil if (@month.nil? && !other.month.nil?) || (!@month.nil? && other.month.nil?)
82
74
 
83
75
  # Return nil if one of the two months is nil
84
- return nil if (@day.nil? && !other.day.nil?) || !@day.nil? && other.day.nil?
76
+ return nil if (@day.nil? && !other.day.nil?) || (!@day.nil? && other.day.nil?)
85
77
 
86
78
  comp_year = @year <=> other.year
87
79
  if comp_year == 0
88
80
  comp_month = @month <=> other.month
89
81
  if comp_month == 0
90
- return @day <=> other.day
82
+ @day <=> other.day
91
83
  else
92
- return comp_month
84
+ comp_month
93
85
  end
94
86
  else
95
87
  comp_year
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'json'
4
- require 'date'
5
- require 'countries'
6
-
7
- require 'metal_archives/middleware/rewrite_endpoint'
3
+ require "json"
4
+ require "date"
5
+ require "countries"
8
6
 
9
7
  module MetalArchives
10
8
  module Parsers
@@ -23,7 +21,7 @@ module MetalArchives
23
21
  #
24
22
  def map_params(query)
25
23
  params = {
26
- :query => query[:name] || ''
24
+ query: query[:name] || "",
27
25
  }
28
26
 
29
27
  params
@@ -42,21 +40,21 @@ module MetalArchives
42
40
  doc = Nokogiri::HTML response
43
41
 
44
42
  # Photo
45
- unless doc.css('.member_img').empty?
46
- photo_uri = URI doc.css('.member_img img').first.attr('src')
43
+ unless doc.css(".member_img").empty?
44
+ photo_uri = URI doc.css(".member_img img").first.attr("src")
47
45
  props[:photo] = Middleware::RewriteEndpoint.rewrite photo_uri
48
46
  end
49
47
 
50
- doc.css('#member_info dl').each do |dl|
51
- dl.css('dt').each do |dt|
48
+ doc.css("#member_info dl").each do |dl|
49
+ dl.css("dt").each do |dt|
52
50
  content = sanitize(dt.next_element.content)
53
51
 
54
- next if content == 'N/A'
52
+ next if content == "N/A"
55
53
 
56
54
  case sanitize(dt.content)
57
- when 'Real/full name:'
55
+ when "Real/full name:"
58
56
  props[:name] = content
59
- when 'Age:'
57
+ when "Age:"
60
58
  date = content.strip.gsub(/[0-9]* *\(born ([^\)]*)\)/, '\1')
61
59
  begin
62
60
  props[:date_of_birth] = NilDate.parse date
@@ -64,24 +62,24 @@ module MetalArchives
64
62
  dob = Date.parse date
65
63
  props[:date_of_birth] = NilDate.new dob.year, dob.month, dob.day
66
64
  end
67
- when 'R.I.P.:'
65
+ when "R.I.P.:"
68
66
  begin
69
67
  dod = Date.parse content
70
68
  props[:date_of_death] = NilDate.new dod.year, dod.month, dod.day
71
69
  rescue ArgumentError => e
72
70
  props[:date_of_death] = NilDate.parse content
73
71
  end
74
- when 'Died of:'
72
+ when "Died of:"
75
73
  props[:cause_of_death] = content
76
- when 'Place of origin:'
77
- props[:country] = ISO3166::Country.find_country_by_name(sanitize(dt.next_element.css('a').first.content))
78
- location = dt.next_element.xpath('text()').map(&:content).join('').strip.gsub(/[()]/, '')
74
+ when "Place of origin:"
75
+ props[:country] = ISO3166::Country.find_country_by_name(sanitize(dt.next_element.css("a").first.content))
76
+ location = dt.next_element.xpath("text()").map(&:content).join("").strip.gsub(/[()]/, "")
79
77
  props[:location] = location unless location.empty?
80
- when 'Gender:'
78
+ when "Gender:"
81
79
  case content
82
- when 'Male'
80
+ when "Male"
83
81
  props[:gender] = :male
84
- when 'Female'
82
+ when "Female"
85
83
  props[:gender] = :female
86
84
  else
87
85
  raise Errors::ParserError, "Unknown gender: #{content}"
@@ -94,11 +92,44 @@ module MetalArchives
94
92
 
95
93
  # Aliases
96
94
  props[:aliases] = []
97
- alt = sanitize doc.css('.band_member_name').first.content
95
+ alt = sanitize doc.css(".band_member_name").first.content
98
96
  props[:aliases] << alt unless props[:name] == alt
99
97
 
98
+ # Active bands
99
+ props[:bands] = []
100
+
101
+ proc = proc do |row|
102
+ link = row.css("h3 a")
103
+ band = if link.any?
104
+ # Band name contains a link
105
+ MetalArchives::Band.find Integer(link.attr("href").text.gsub(%r(^.*/([^/#]*)#.*$), '\1'))
106
+ else
107
+ # Band name does not contain a link
108
+ sanitize row.css("h3").text
109
+ end
110
+
111
+ r = row.css(".member_in_band_role")
112
+
113
+ range = parse_year_range r.xpath("text()").map(&:content).join("").strip.gsub(/[\n\r\t]/, "").gsub(/.*\((.*)\)/, '\1')
114
+ role = sanitize r.css("strong").first.content
115
+
116
+ {
117
+ band: band,
118
+ date_active: range,
119
+ role: role,
120
+ }
121
+ end
122
+
123
+ doc.css("#artist_tab_active .member_in_band").each do |row|
124
+ props[:bands] << proc.call(row).merge(active: true)
125
+ end
126
+
127
+ doc.css("#artist_tab_past .member_in_band").each do |row|
128
+ props[:bands] << proc.call(row).merge(active: false)
129
+ end
130
+
100
131
  props
101
- rescue => e
132
+ rescue StandardError => e
102
133
  e.backtrace.each { |b| MetalArchives.config.logger.error b }
103
134
  raise Errors::ParserError, e
104
135
  end
@@ -119,25 +150,25 @@ module MetalArchives
119
150
  # Default to official links
120
151
  type = :official
121
152
 
122
- doc.css('#linksTablemain tr').each do |row|
123
- if row['id'].match /^header_/
124
- type = row['id'].gsub(/^header_/, '').downcase.to_sym
153
+ doc.css("#linksTablemain tr").each do |row|
154
+ if row["id"].match /^header_/
155
+ type = row["id"].gsub(/^header_/, "").downcase.to_sym
125
156
  else
126
- a = row.css('td a').first
157
+ a = row.css("td a").first
127
158
 
128
159
  # No links have been added yet
129
160
  next unless a
130
161
 
131
162
  links << {
132
- :url => a['href'],
133
- :type => type,
134
- :title => a.content
163
+ url: a["href"],
164
+ type: type,
165
+ title: a.content,
135
166
  }
136
167
  end
137
168
  end
138
169
 
139
170
  links
140
- rescue => e
171
+ rescue StandardError => e
141
172
  e.backtrace.each { |b| MetalArchives.config.logger.error b }
142
173
  raise Errors::ParserError, e
143
174
  end
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
- require 'json'
3
- require 'date'
4
- require 'countries'
2
+
3
+ require "json"
4
+ require "date"
5
+ require "countries"
5
6
 
6
7
  module MetalArchives
7
8
  module Parsers
@@ -20,22 +21,22 @@ module MetalArchives
20
21
  #
21
22
  def map_params(query)
22
23
  params = {
23
- :bandName => query[:name] || '',
24
- :exactBandMatch => (!!query[:exact] ? 1 : 0),
25
- :genre => query[:genre] || '',
26
- :yearCreationFrom => (query[:year] && query[:year].begin ? query[:year].begin.year : '') || '',
27
- :yearCreationTo => (query[:year] && query[:year].end ? query[:year].end.year : '') || '',
28
- :bandNotes => query[:comment] || '',
29
- :status => map_status(query[:status]),
30
- :themes => query[:lyrical_themes] || '',
31
- :location => query[:location] || '',
32
- :bandLabelName => query[:label] || '',
33
- :indieLabelBand => (!!query[:independent] ? 1 : 0)
24
+ bandName: query[:name] || "",
25
+ exactBandMatch: (query[:exact] ? 1 : 0),
26
+ genre: query[:genre] || "",
27
+ yearCreationFrom: (query[:year]&.begin ? query[:year].begin.year : "") || "",
28
+ yearCreationTo: (query[:year]&.end ? query[:year].end.year : "") || "",
29
+ bandNotes: query[:comment] || "",
30
+ status: map_status(query[:status]),
31
+ themes: query[:lyrical_themes] || "",
32
+ location: query[:location] || "",
33
+ bandLabelName: query[:label] || "",
34
+ indieLabelBand: (query[:independent] ? 1 : 0),
34
35
  }
35
36
 
36
37
  params[:country] = []
37
38
  Array(query[:country]).each do |country|
38
- params[:country] << (country.is_a?(ISO3166::Country) ? country.alpha2 : (country || ''))
39
+ params[:country] << (country.is_a?(ISO3166::Country) ? country.alpha2 : (country || ""))
39
40
  end
40
41
  params[:country] = params[:country].first if params[:country].size == 1
41
42
 
@@ -54,64 +55,64 @@ module MetalArchives
54
55
  props = {}
55
56
  doc = Nokogiri::HTML response
56
57
 
57
- props[:name] = sanitize doc.css('#band_info .band_name a').first.content
58
+ props[:name] = sanitize doc.css("#band_info .band_name a").first.content
58
59
 
59
60
  props[:aliases] = []
60
61
 
61
62
  # Logo
62
- unless doc.css('.band_name_img').empty?
63
- logo_uri = URI doc.css('.band_name_img img').first.attr('src')
63
+ unless doc.css(".band_name_img").empty?
64
+ logo_uri = URI doc.css(".band_name_img img").first.attr("src")
64
65
  props[:logo] = Middleware::RewriteEndpoint.rewrite logo_uri
65
66
  end
66
67
 
67
68
  # Photo
68
- unless doc.css('.band_img').empty?
69
- photo_uri = URI doc.css('.band_img img').first.attr('src')
69
+ unless doc.css(".band_img").empty?
70
+ photo_uri = URI doc.css(".band_img img").first.attr("src")
70
71
  props[:photo] = Middleware::RewriteEndpoint.rewrite photo_uri
71
72
  end
72
73
 
73
- doc.css('#band_stats dl').each do |dl|
74
- dl.search('dt').each do |dt|
74
+ doc.css("#band_stats dl").each do |dl|
75
+ dl.search("dt").each do |dt|
75
76
  content = sanitize(dt.next_element.content)
76
77
 
77
- next if content == 'N/A'
78
+ next if content == "N/A"
78
79
 
79
80
  case dt.content
80
- when 'Country of origin:'
81
- props[:country] = ISO3166::Country.find_country_by_name sanitize(dt.next_element.css('a').first.content)
82
- when 'Location:'
81
+ when "Country of origin:"
82
+ props[:country] = ISO3166::Country.find_country_by_name sanitize(dt.next_element.css("a").first.content)
83
+ when "Location:"
83
84
  props[:location] = content
84
- when 'Status:'
85
- props[:status] = content.downcase.tr(' ', '_').to_sym
86
- when 'Formed in:'
85
+ when "Status:"
86
+ props[:status] = content.downcase.tr(" ", "_").to_sym
87
+ when "Formed in:"
87
88
  begin
88
89
  dof = Date.parse content
89
90
  props[:date_formed] = NilDate.new dof.year, dof.month, dof.day
90
91
  rescue ArgumentError => e
91
92
  props[:date_formed] = NilDate.parse content
92
93
  end
93
- when 'Genre:'
94
+ when "Genre:"
94
95
  props[:genres] = parse_genre content
95
- when 'Lyrical themes:'
96
+ when "Lyrical themes:"
96
97
  props[:lyrical_themes] = []
97
- content.split(',').each do |theme|
98
+ content.split(",").each do |theme|
98
99
  t = theme.split.map(&:capitalize)
99
- t.delete '(early)'
100
- t.delete '(later)'
101
- props[:lyrical_themes] << t.join(' ')
100
+ t.delete "(early)"
101
+ t.delete "(later)"
102
+ props[:lyrical_themes] << t.join(" ")
102
103
  end
103
104
  when /(Current|Last) label:/
104
- props[:independent] = (content == 'Unsigned/independent')
105
- # TODO
106
- when 'Years active:'
105
+ props[:independent] = (content == "Unsigned/independent")
106
+ # TODO: label
107
+ when "Years active:"
107
108
  props[:date_active] = []
108
- content.split(',').each do |range|
109
+ content.split(",").each do |range|
109
110
  # Aliases
110
111
  range.scan(/\(as ([^)]*)\)/).each { |name| props[:aliases] << name.first }
111
112
  # Ranges
112
- r = range.gsub(/ *\(as ([^)]*)\) */, '').strip.split('-')
113
- date_start = (r.first == '?' ? nil : Date.new(r.first.to_i))
114
- date_end = (r.last ==( '?') || r.last == 'present' ? nil : Date.new(r.first.to_i))
113
+ r = range.gsub(/ *\(as ([^)]*)\) */, "").strip.split("-")
114
+ date_start = (r.first == "?" ? nil : NilDate.new(r.first.to_i))
115
+ date_end = (r.last == "?" || r.last == "present" ? nil : NilDate.new(r.first.to_i))
115
116
  props[:date_active] << MetalArchives::Range.new(date_start, date_end)
116
117
  end
117
118
  else
@@ -121,9 +122,9 @@ module MetalArchives
121
122
  end
122
123
 
123
124
  props
124
- rescue => e
125
+ rescue StandardError => e
125
126
  e.backtrace.each { |b| MetalArchives.config.logger.error b }
126
- raise Errors::ParserError, e
127
+ raise MetalArchives::Errors::ParserError, e
127
128
  end
128
129
 
129
130
  ##
@@ -138,17 +139,17 @@ module MetalArchives
138
139
  similar = []
139
140
 
140
141
  doc = Nokogiri::HTML response
141
- doc.css('#artist_list tbody tr').each do |row|
142
+ doc.css("#artist_list tbody tr").each do |row|
142
143
  similar << {
143
- :band => MetalArchives::Band.new(:id => row.css('td a').first['href'].split('/').last.to_i),
144
- :score => row.css('td').last.content.strip
144
+ band: MetalArchives::Band.new(id: row.css("td a").first["href"].split("/").last.to_i),
145
+ score: row.css("td").last.content.strip,
145
146
  }
146
147
  end
147
148
 
148
149
  similar
149
- rescue => e
150
+ rescue StandardError => e
150
151
  e.backtrace.each { |b| MetalArchives.config.logger.error b }
151
- raise Errors::ParserError, e
152
+ raise MetalArchives::Errors::ParserError, e
152
153
  end
153
154
 
154
155
  ##
@@ -163,46 +164,68 @@ module MetalArchives
163
164
  links = []
164
165
 
165
166
  doc = Nokogiri::HTML response
166
- doc.css('#linksTableOfficial td a').each do |a|
167
+ doc.css("#linksTableOfficial td a").each do |a|
167
168
  links << {
168
- :url => a['href'],
169
- :type => :official,
170
- :title => a.content
169
+ url: a["href"],
170
+ type: :official,
171
+ title: a.content,
171
172
  }
172
173
  end
173
- doc.css('#linksTableOfficial_merchandise td a').each do |a|
174
+ doc.css("#linksTableOfficial_merchandise td a").each do |a|
174
175
  links << {
175
- :url => a['href'],
176
- :type => :merchandise,
177
- :title => a.content
176
+ url: a["href"],
177
+ type: :merchandise,
178
+ title: a.content,
178
179
  }
179
180
  end
180
181
 
181
182
  links
182
- rescue => e
183
+ rescue StandardError => e
183
184
  e.backtrace.each { |b| MetalArchives.config.logger.error b }
184
- raise Errors::ParserError, e
185
+ raise MetalArchives::Errors::ParserError, e
186
+ end
187
+
188
+ ##
189
+ # Parse releases HTML page
190
+ #
191
+ # Returns +Array+
192
+ # [Raises]
193
+ # - rdoc-ref:MetalArchives::Errors::ParserError when parsing failed. Please report this error.
194
+ #
195
+ def parse_releases_html(response)
196
+ releases = []
197
+
198
+ doc = Nokogiri::HTML response
199
+ doc.css("tbody tr td:first a").each do |a|
200
+ id = a["href"].split("/").last.to_i
201
+ releases << MetalArchives::Release.find(id)
202
+ end
203
+
204
+ releases
205
+ rescue StandardError => e
206
+ e.backtrace.each { |b| MetalArchives.config.logger.error b }
207
+ raise MetalArchives::Errors::ParserError, e
185
208
  end
186
209
 
187
210
  private
188
211
 
189
- ##
190
- # Map MA band status
191
- #
192
- # Returns +Symbol+
193
- #
194
- # [Raises]
195
- # - rdoc-ref:MetalArchives::Errors::ParserError when parsing failed. Please report this error.
196
- #
212
+ ##
213
+ # Map MA band status
214
+ #
215
+ # Returns +Symbol+
216
+ #
217
+ # [Raises]
218
+ # - rdoc-ref:MetalArchives::Errors::ParserError when parsing failed. Please report this error.
219
+ #
197
220
  def map_status(status)
198
221
  s = {
199
- nil => '',
200
- :active => 'Active',
201
- :split_up => 'Split-up',
202
- :on_hold => 'On hold',
203
- :unknown => 'Unknown',
204
- :changed_name => 'Changed name',
205
- :disputed => 'Disputed'
222
+ nil => "",
223
+ :active => "Active",
224
+ :split_up => "Split-up",
225
+ :on_hold => "On hold",
226
+ :unknown => "Unknown",
227
+ :changed_name => "Changed name",
228
+ :disputed => "Disputed",
206
229
  }
207
230
 
208
231
  raise MetalArchives::Errors::ParserError, "Unknown status: #{status}" unless s[status]