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
data/Rakefile CHANGED
@@ -1,16 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rake'
4
- require 'rake/testtask'
3
+ require "rake"
4
+ require "rake/testtask"
5
+ require "zeitwerk"
5
6
 
6
7
  Rake::TestTask.new do |t|
7
- t.libs << 'test'
8
- t.test_files = FileList['test/*/*_test.rb']
8
+ t.libs << "test"
9
+ t.test_files = FileList["test/*/*_test.rb"]
9
10
  t.verbose = true
10
11
  end
11
12
 
12
- require 'rdoc/task'
13
+ require "rdoc/task"
13
14
  RDoc::Task.new do |rdoc|
14
- rdoc.main = 'README.md'
15
- rdoc.rdoc_files.include('README.md', 'lib/**/*.rb')
15
+ rdoc.main = "README.md"
16
+ rdoc.rdoc_files.include("README.md", "lib/**/*.rb")
16
17
  end
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "logger"
5
+
6
+ require "bundler/setup"
7
+ require "metal_archives"
8
+
9
+ # You can add fixtures and/or initialization code here to make experimenting
10
+ # with your gem easier. You can also use a different console, if you like.
11
+
12
+ MetalArchives.configure do |c|
13
+ ## Application identity (required)
14
+ c.app_name = "My App"
15
+ c.app_version = "1.0"
16
+ c.app_contact = "support@mymusicapp.com"
17
+
18
+ ## Request throttling (optional, overrides defaults)
19
+ # c.request_rate = 1
20
+ # c.request_timeout = 3
21
+
22
+ ## Connect additional Faraday middleware
23
+ # c.middleware = [MyMiddleware, MyOtherMiddleware]
24
+
25
+ ## Custom cache size per object class (optional, overrides defaults)
26
+ # c.cache_size = 100
27
+
28
+ ## Metal Archives endpoint (optional, overrides default)
29
+ # c.endpoint = "http://www.metal-archives.com/"
30
+
31
+ ## Custom logger (optional)
32
+ c.logger = Logger.new STDOUT
33
+ c.logger.level = Logger::WARN
34
+ end
35
+
36
+ # (If you use this, don't forget to add pry to your Gemfile!)
37
+ # require "pry"
38
+ # Pry.start
39
+
40
+ require "irb"
41
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,14 @@
1
+ version: "3.7"
2
+
3
+ services:
4
+ nginx:
5
+ image: nginx:alpine
6
+ ports:
7
+ - "80:80"
8
+ volumes:
9
+ - ./nginx/:/etc/nginx/conf.d/
10
+ - nginx:/cache/
11
+ restart: always
12
+
13
+ volumes:
14
+ nginx:
@@ -1,37 +1,56 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'openssl'
4
-
5
- require 'metal_archives/middleware/headers'
6
- require 'metal_archives/middleware/cache_check'
7
- require 'metal_archives/middleware/rewrite_endpoint'
8
- require 'metal_archives/middleware/encoding'
9
-
10
- require 'metal_archives/version'
11
- require 'metal_archives/configuration'
12
- require 'metal_archives/error'
13
-
14
- require 'metal_archives/utils/range'
15
- require 'metal_archives/utils/collection'
16
- require 'metal_archives/utils/lru_cache'
17
- require 'metal_archives/utils/nil_date'
18
-
19
- require 'metal_archives/models/base_model'
20
- require 'metal_archives/models/label'
21
- require 'metal_archives/models/artist'
22
- require 'metal_archives/models/band'
23
- require 'metal_archives/models/release'
24
-
25
- require 'metal_archives/parsers/parser'
26
- require 'metal_archives/parsers/label'
27
- require 'metal_archives/parsers/artist'
28
- require 'metal_archives/parsers/band'
29
- require 'metal_archives/parsers/release'
30
-
31
- require 'metal_archives/http_client'
3
+ require "openssl"
4
+
5
+ require "zeitwerk"
6
+ loader = Zeitwerk::Loader.for_gem
7
+ load.enable_reloading if ENV["METAL_ARCHIVES_ENV"] == "development"
8
+ loader.inflector.inflect(
9
+ "id" => "ID",
10
+ "api" => "API",
11
+ "http_client" => "HTTPClient",
12
+ "lru_cache" => "LRUCache"
13
+ )
14
+ loader.collapse("lib/metal_archives/models")
15
+ loader.setup
32
16
 
33
17
  ##
34
18
  # Metal Archives Ruby API
35
19
  #
36
20
  module MetalArchives
21
+ class << self
22
+ ##
23
+ # API configuration
24
+ #
25
+ # Instance of rdoc-ref:MetalArchives::Configuration
26
+ #
27
+ def config
28
+ raise MetalArchives::Errors::InvalidConfigurationError, "Gem has not been configured" unless @config
29
+
30
+ @config
31
+ end
32
+
33
+ ##
34
+ # Configure API options.
35
+ #
36
+ # A block must be specified, to which a
37
+ # rdoc-ref:MetalArchives::Configuration parameter will be passed.
38
+ #
39
+ # [Raises]
40
+ # - rdoc-ref:InvalidConfigurationException
41
+ #
42
+ def configure
43
+ raise MetalArchives::Errors::InvalidConfigurationError, "No configuration block given" unless block_given?
44
+
45
+ @config = MetalArchives::Configuration.new
46
+ yield @config
47
+
48
+ raise MetalArchives::Errors::InvalidConfigurationError, "app_name has not been configured" unless MetalArchives.config.app_name && !MetalArchives.config.app_name.empty?
49
+ raise MetalArchives::Errors::InvalidConfigurationError, "app_version has not been configured" unless MetalArchives.config.app_version && !MetalArchives.config.app_version.empty?
50
+
51
+ return if MetalArchives.config.app_contact && !MetalArchives.config.app_contact.empty?
52
+
53
+ raise MetalArchives::Errors::InvalidConfigurationError, "app_contact has not been configured"
54
+ end
55
+ end
37
56
  end
@@ -1,38 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module MetalArchives
4
- class << self
5
- ##
6
- # API configuration
7
- #
8
- # Instance of rdoc-ref:MetalArchives::Configuration
9
- #
10
- def config
11
- raise MetalArchives::Errors::InvalidConfigurationError, 'Gem has not been configured' unless @config
12
-
13
- @config
14
- end
15
-
16
- ##
17
- # Configure API options.
18
- #
19
- # A block must be specified, to which a
20
- # rdoc-ref:MetalArchives::Configuration parameter will be passed.
21
- #
22
- # [Raises]
23
- # - rdoc-ref:InvalidConfigurationException
24
- #
25
- def configure
26
- raise MetalArchives::Errors::InvalidConfigurationError, 'No configuration block given' unless block_given?
27
- @config = MetalArchives::Configuration.new
28
- yield @config
29
-
30
- raise MetalArchives::Errors::InvalidConfigurationError, 'app_name has not been configured' unless MetalArchives.config.app_name && !MetalArchives.config.app_name.empty?
31
- raise MetalArchives::Errors::InvalidConfigurationError, 'app_version has not been configured' unless MetalArchives.config.app_version && !MetalArchives.config.app_version.empty?
32
- raise MetalArchives::Errors::InvalidConfigurationError, 'app_contact has not been configured' unless MetalArchives.config.app_contact && !MetalArchives.config.app_contact.empty?
33
- end
34
- end
3
+ require "logger"
35
4
 
5
+ module MetalArchives
36
6
  ##
37
7
  # Contains configuration options
38
8
  #
@@ -58,6 +28,12 @@ module MetalArchives
58
28
  attr_accessor :endpoint
59
29
  attr_reader :default_endpoint
60
30
 
31
+ ##
32
+ # Endpoint HTTP Basic authentication
33
+ #
34
+ attr_accessor :endpoint_user
35
+ attr_accessor :endpoint_password
36
+
61
37
  ##
62
38
  # Additional Faraday middleware
63
39
  #
@@ -87,7 +63,7 @@ module MetalArchives
87
63
  # Default configuration values
88
64
  #
89
65
  def initialize
90
- @default_endpoint = 'https://www.metal-archives.com/'
66
+ @default_endpoint = "https://www.metal-archives.com/"
91
67
  @throttle_rate = 1
92
68
  @throttle_wait = 3
93
69
  @logger = Logger.new STDOUT
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'faraday'
4
- require 'faraday_throttler'
3
+ require "faraday"
4
+ require "faraday_throttler"
5
5
 
6
6
  module MetalArchives
7
7
  ##
@@ -23,7 +23,7 @@ module MetalArchives
23
23
  raise Errors::APIError, response.status if response.status >= 400
24
24
 
25
25
  response
26
- rescue Faraday::Error::ClientError => e
26
+ rescue Faraday::ClientError => e
27
27
  MetalArchives.config.logger.error e.response
28
28
  raise Errors::APIError, e
29
29
  end
@@ -35,7 +35,7 @@ module MetalArchives
35
35
  #
36
36
  #
37
37
  def client
38
- raise Errors::InvalidConfigurationError, 'Not configured yet' unless MetalArchives.config
38
+ raise Errors::InvalidConfigurationError, "Not configured yet" unless MetalArchives.config
39
39
 
40
40
  @faraday ||= Faraday.new do |f|
41
41
  f.request :url_encoded # form-encode POST params
@@ -46,14 +46,19 @@ module MetalArchives
46
46
  f.use MetalArchives::Middleware::RewriteEndpoint
47
47
  f.use MetalArchives::Middleware::Encoding
48
48
 
49
- MetalArchives.config.middleware.each { |m| f.use m } if MetalArchives.config.middleware
49
+ MetalArchives.config.middleware&.each { |m| f.use m }
50
50
 
51
51
  f.use :throttler,
52
- :rate => MetalArchives.config.request_rate,
53
- :wait => MetalArchives.config.request_timeout,
54
- :logger => MetalArchives.config.logger
52
+ rate: MetalArchives.config.request_rate,
53
+ wait: MetalArchives.config.request_timeout,
54
+ logger: MetalArchives.config.logger
55
55
 
56
56
  f.adapter Faraday.default_adapter
57
+
58
+ next unless MetalArchives.config.endpoint_user
59
+
60
+ f.basic_auth MetalArchives.config.endpoint_user,
61
+ MetalArchives.config.endpoint_password
57
62
  end
58
63
  end
59
64
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'faraday'
3
+ require "faraday"
4
4
 
5
5
  module MetalArchives
6
6
  module Middleware
@@ -11,9 +11,7 @@ module MetalArchives
11
11
  def on_complete(env)
12
12
  return unless MetalArchives.config.endpoint
13
13
 
14
- if env[:response_headers].has_key? 'x-cache-status'
15
- MetalArchives.config.logger.info "Cache #{env[:response_headers]['x-cache-status'].downcase} for #{env.url.to_s}"
16
- end
14
+ MetalArchives.config.logger.info "Cache #{env[:response_headers]['x-cache-status'].downcase} for #{env.url}" if env[:response_headers].key? "x-cache-status"
17
15
  end
18
16
  end
19
17
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'faraday'
3
+ require "faraday"
4
4
 
5
5
  module MetalArchives
6
6
  module Middleware
@@ -9,7 +9,7 @@ module MetalArchives
9
9
  #
10
10
  class Encoding < Faraday::Response::Middleware # :nodoc:
11
11
  def on_complete(env)
12
- env.response.body.force_encoding('utf-8')
12
+ env.response.body.force_encoding("utf-8")
13
13
  end
14
14
  end
15
15
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'faraday'
3
+ require "faraday"
4
4
 
5
5
  module MetalArchives
6
6
  module Middleware
@@ -10,9 +10,9 @@ module MetalArchives
10
10
  class Headers < Faraday::Middleware # :nodoc:
11
11
  def call(env)
12
12
  headers = {
13
- 'User-Agent' => user_agent_string,
14
- 'Via' => via_string,
15
- 'Accept' => accept_string
13
+ "User-Agent" => user_agent_string,
14
+ "Via" => via_string,
15
+ "Accept" => accept_string,
16
16
  }
17
17
 
18
18
  env[:request_headers].merge! headers
@@ -27,7 +27,7 @@ module MetalArchives
27
27
  end
28
28
 
29
29
  def accept_string
30
- 'application/json'
30
+ "application/json"
31
31
  end
32
32
 
33
33
  def via_string
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'faraday'
3
+ require "faraday"
4
4
 
5
5
  module MetalArchives
6
6
  module Middleware
@@ -27,7 +27,7 @@ module MetalArchives
27
27
  new_uri.host = rewritten_uri.host
28
28
  new_uri.scheme = rewritten_uri.scheme
29
29
 
30
- MetalArchives.config.logger.debug "Rewrite #{uri.to_s} to #{new_uri}"
30
+ MetalArchives.config.logger.debug "Rewrite #{uri} to #{new_uri}"
31
31
  end
32
32
 
33
33
  new_uri
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'date'
4
- require 'countries'
3
+ require "date"
4
+ require "countries"
5
+ require "nokogiri"
5
6
 
6
7
  module MetalArchives
7
8
  ##
@@ -13,7 +14,7 @@ module MetalArchives
13
14
  #
14
15
  # Returns +Integer+
15
16
  #
16
- property :id, :type => Integer
17
+ property :id, type: Integer
17
18
 
18
19
  ##
19
20
  # :attr_reader: name
@@ -35,7 +36,7 @@ module MetalArchives
35
36
  # - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
36
37
  # - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
37
38
  #
38
- property :aliases, :multiple => true
39
+ property :aliases, multiple: true
39
40
 
40
41
  ##
41
42
  # :attr_reader: country
@@ -46,7 +47,7 @@ module MetalArchives
46
47
  # - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
47
48
  # - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
48
49
  #
49
- property :country, :type => ISO3166::Country
50
+ property :country, type: ISO3166::Country
50
51
 
51
52
  ##
52
53
  # :attr_reader: location
@@ -68,7 +69,7 @@ module MetalArchives
68
69
  # - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
69
70
  # - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
70
71
  #
71
- property :date_of_birth, :type => NilDate
72
+ property :date_of_birth, type: NilDate
72
73
 
73
74
  ##
74
75
  # :attr_reader: date_of_death
@@ -79,7 +80,7 @@ module MetalArchives
79
80
  # - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
80
81
  # - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
81
82
  #
82
- property :date_of_death, :type => NilDate
83
+ property :date_of_death, type: NilDate
83
84
 
84
85
  ##
85
86
  # :attr_reader: cause_of_death
@@ -101,7 +102,7 @@ module MetalArchives
101
102
  # - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
102
103
  # - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
103
104
  #
104
- enum :gender, :values => %i[male female]
105
+ enum :gender, values: %i(male female)
105
106
 
106
107
  ##
107
108
  # :attr_reader: biography
@@ -145,17 +146,32 @@ module MetalArchives
145
146
  # - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
146
147
  # - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
147
148
  #
148
- # [+similar+]
149
+ # [+links+]
149
150
  # - +:url+: +String+
150
151
  # - +:type+: +Symbol+, either +:official+, +:unofficial+ or +:unlisted_bands+
151
152
  # - +:title+: +String+
152
153
  #
153
- property :links, :multiple => true
154
+ property :links, multiple: true
154
155
 
155
- # TODO: active bands/albums
156
- # TODO: past bands/albums
157
- # TODO: guest bands/albums
158
- # TODO: misc bands/albums
156
+ ##
157
+ # :attr_reader: bands
158
+ #
159
+ # Returns +Array+ of +Hash+ containing the following keys
160
+ #
161
+ # [Raises]
162
+ # - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
163
+ # - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
164
+ #
165
+ # [+bands+]
166
+ # - +:band+: rdoc-ref:Band
167
+ # - +:active+: Boolean
168
+ # - +:date_active+: +Array+ of rdoc-ref:Range containing rdoc-ref:NilDate
169
+ # - +:role+: +String+
170
+ #
171
+ property :bands, type: Hash, multiple: true
172
+
173
+ # TODO: guest/session bands
174
+ # TODO: misc bands
159
175
 
160
176
  protected
161
177
 
@@ -206,7 +222,7 @@ module MetalArchives
206
222
  def find(id)
207
223
  return cache[id] if cache.include? id
208
224
 
209
- Artist.new :id => id
225
+ Artist.new id: id
210
226
  end
211
227
 
212
228
  ##
@@ -252,10 +268,10 @@ module MetalArchives
252
268
  response = HTTPClient.get url, params
253
269
  json = JSON.parse response.body
254
270
 
255
- return nil if json['aaData'].empty?
271
+ return nil if json["aaData"].empty?
256
272
 
257
- data = json['aaData'].first
258
- id = Nokogiri::HTML(data.first).xpath('//a/@href').first.value.delete('\\').split('/').last.gsub(/\D/, '').to_i
273
+ data = json["aaData"].first
274
+ id = Nokogiri::HTML(data.first).xpath("//a/@href").first.value.delete('\\').split("/").last.gsub(/\D/, "").to_i
259
275
 
260
276
  find id
261
277
  end
@@ -299,7 +315,7 @@ module MetalArchives
299
315
  raise MetalArchives::Errors::ArgumentError unless name.is_a? String
300
316
 
301
317
  url = "#{MetalArchives.config.default_endpoint}search/ajax-artist-search/"
302
- query = { :name => name }
318
+ query = { name: name }
303
319
 
304
320
  params = Parsers::Artist.map_params query
305
321
 
@@ -309,16 +325,16 @@ module MetalArchives
309
325
  if @max_items && @start >= @max_items
310
326
  []
311
327
  else
312
- response = HTTPClient.get url, params.merge(:iDisplayStart => @start)
328
+ response = HTTPClient.get url, params.merge(iDisplayStart: @start)
313
329
  json = JSON.parse response.body
314
330
 
315
- @max_items = json['iTotalRecords']
331
+ @max_items = json["iTotalRecords"]
316
332
 
317
333
  objects = []
318
334
 
319
- json['aaData'].each do |data|
335
+ json["aaData"].each do |data|
320
336
  # Create Artist object for every ID in the results list
321
- id = Nokogiri::HTML(data.first).xpath('//a/@href').first.value.delete('\\').split('/').last.gsub(/\D/, '').to_i
337
+ id = Nokogiri::HTML(data.first).xpath("//a/@href").first.value.delete('\\').split("/").last.gsub(/\D/, "").to_i
322
338
  objects << Artist.find(id)
323
339
  end
324
340
 
@@ -341,7 +357,7 @@ module MetalArchives
341
357
  # - rdoc-ref:MetalArchives::Errors::ParserError when parsing failed. Please report this error.
342
358
  #
343
359
  def all
344
- search ''
360
+ search ""
345
361
  end
346
362
  end
347
363
  end