metal_archives 0.8.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +59 -7
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +14 -0
  5. data/.travis.yml +11 -0
  6. data/Gemfile +2 -0
  7. data/{LICENSE → LICENSE.md} +0 -0
  8. data/README.md +77 -9
  9. data/Rakefile +5 -3
  10. data/lib/metal_archives.rb +8 -0
  11. data/lib/metal_archives/configuration.rb +28 -7
  12. data/lib/metal_archives/error.rb +37 -30
  13. data/lib/metal_archives/http_client.rb +21 -42
  14. data/lib/metal_archives/middleware/headers.rb +38 -0
  15. data/lib/metal_archives/middleware/rewrite_endpoint.rb +38 -0
  16. data/lib/metal_archives/models/artist.rb +51 -65
  17. data/lib/metal_archives/models/band.rb +41 -39
  18. data/lib/metal_archives/models/base_model.rb +88 -59
  19. data/lib/metal_archives/models/label.rb +7 -6
  20. data/lib/metal_archives/parsers/artist.rb +110 -99
  21. data/lib/metal_archives/parsers/band.rb +168 -156
  22. data/lib/metal_archives/parsers/label.rb +54 -52
  23. data/lib/metal_archives/parsers/parser.rb +73 -71
  24. data/lib/metal_archives/utils/collection.rb +7 -1
  25. data/lib/metal_archives/utils/lru_cache.rb +11 -4
  26. data/lib/metal_archives/utils/nil_date.rb +54 -0
  27. data/lib/metal_archives/utils/range.rb +16 -8
  28. data/lib/metal_archives/version.rb +3 -1
  29. data/metal_archives.gemspec +21 -11
  30. data/spec/configuration_spec.rb +101 -0
  31. data/spec/factories/artist_factory.rb +37 -0
  32. data/spec/factories/band_factory.rb +60 -0
  33. data/spec/factories/nil_date_factory.rb +9 -0
  34. data/spec/factories/range_factory.rb +8 -0
  35. data/spec/models/artist_spec.rb +142 -0
  36. data/spec/models/band_spec.rb +179 -0
  37. data/spec/models/base_model_spec.rb +217 -0
  38. data/spec/parser_spec.rb +19 -0
  39. data/spec/spec_helper.rb +111 -0
  40. data/spec/support/factory_girl.rb +5 -0
  41. data/spec/support/metal_archives.rb +26 -0
  42. data/spec/utils/collection_spec.rb +72 -0
  43. data/spec/utils/lru_cache_spec.rb +53 -0
  44. data/spec/utils/nil_date_spec.rb +98 -0
  45. data/spec/utils/range_spec.rb +62 -0
  46. metadata +142 -57
  47. data/test/base_model_test.rb +0 -111
  48. data/test/configuration_test.rb +0 -57
  49. data/test/parser_test.rb +0 -37
  50. data/test/property/artist_property_test.rb +0 -43
  51. data/test/property/band_property_test.rb +0 -94
  52. data/test/query/artist_query_test.rb +0 -109
  53. data/test/query/band_query_test.rb +0 -152
  54. data/test/test_helper.rb +0 -25
  55. data/test/utils/collection_test.rb +0 -51
  56. data/test/utils/lru_cache_test.rb +0 -22
  57. data/test/utils/range_test.rb +0 -42
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e19af43a38aa2f5242fee7553c145f673811af35
4
- data.tar.gz: 05f2f5ad5b31fa0b8fa095f9866f6b4d148ce4c3
3
+ metadata.gz: 9c1527cbe8ea9df768ea3112b958fbba43f29dd0
4
+ data.tar.gz: 82971bd30252efb8e77badb9dfe10c71fb86a585
5
5
  SHA512:
6
- metadata.gz: 73946de65fb4d67fc98591a897bd9045db3c483e39084656ec4b4e39fa49b247ccd892aeca6f7565969c3522c8772ac0ae6d577ed1d6c6a7d7797fd960dabf89
7
- data.tar.gz: 1f2bba663937069139bbd0d2a0093e9e95b7e547f1a1b7a4e0f3e4e3a40790a9f4780cecaf5804677c02fc1df44f2c3c74b938930a97c6c6c5cd29ebcd1bcc71
6
+ metadata.gz: 64fb61f7acd105d6aa93f005cccdc1d246de4ac7b9a2fc4f944c7a3ff729698eaedd42faee4228f25549f33beedef1f5d34d3834953abe59054f16161b4dcea0
7
+ data.tar.gz: e57bc2994341940aa33f283ae028ca3cb7a51f1e634eee3041c66d3d75ff0d765ee93e87cf30d394a6cc9ade61d8458bdab08fb5e4bc5dd5d45ec146fe43d38b
data/.gitignore CHANGED
@@ -1,12 +1,64 @@
1
- # Ruby version
1
+ Gemfile.lock
2
+ .idea
3
+
4
+ *.gem
5
+ *.rbc
6
+ /.config
7
+ /coverage/
8
+ /InstalledFiles
9
+ /pkg/
10
+ /spec/reports/
11
+ /spec/examples.txt
12
+ /test/tmp/
13
+ /test/version_tmp/
14
+ /tmp/
15
+
16
+ # Used by dotenv library to load environment variables.
17
+ # .env
18
+
19
+ ## Specific to RubyMotion:
20
+ .dat*
21
+ .repl_history
22
+ build/
23
+ *.bridgesupport
24
+ build-iPhoneOS/
25
+ build-iPhoneSimulator/
26
+
27
+ ## Specific to RubyMotion (use of CocoaPods):
28
+ #
29
+ # We recommend against adding the Pods directory to your .gitignore. However
30
+ # you should judge for yourself, the pros and cons are mentioned at:
31
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
32
+ #
33
+ # vendor/Pods/
34
+
35
+ ## Documentation cache and generated files:
36
+ /.yardoc/
37
+ /_yardoc/
38
+ /doc/
39
+ /rdoc/
40
+
41
+ ## Environment normalization:
42
+ /.bundle/
43
+ /vendor/bundle
44
+ /lib/bundler/man/
45
+
46
+ # for a library or gem, you might want to ignore these files since the code is
47
+ # intended to run in multiple environments; otherwise, check them in:
48
+ # Gemfile.lock
49
+ # .ruby-version
50
+ # .ruby-gemset
51
+
52
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
53
+ .rvmrc
54
+
55
+ # IDE files
56
+ .idea
57
+
58
+ ## Gem files
2
59
  .ruby-version
3
60
  .ruby-gemset
4
61
 
5
- # Temp files
62
+ ## Temp files
6
63
  .byebug_history
7
-
8
- # RDoc
9
64
  html/
10
-
11
- Gemfile.lock
12
- .idea
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,14 @@
1
+ Metrics/LineLength:
2
+ Max: 120
3
+
4
+ Metrics/MethodLength:
5
+ Enabled: false
6
+
7
+ Metrics/BlockLength:
8
+ Enabled: false
9
+
10
+ Style/HashSyntax:
11
+ EnforcedStyle: hash_rockets
12
+
13
+ Style/NestedParenthesizedCalls:
14
+ Enabled: false
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.4.1
4
+ cache:
5
+ bundler: true
6
+ env:
7
+ - RAILS_ENV=test CI=true TRAVIS=true
8
+ install:
9
+ - bundle install
10
+ script:
11
+ - bundle exec rspec
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  gemspec
File without changes
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Metal Archives Web Service Wrapper
1
+ # Metal Archives Web Service Wrapper [![Travis](https://travis-ci.org/floriandejonckheere/metal_archives.svg?branch=master)](https://travis-ci.org/floriandejonckheere/metal_archives) [![Coverage Status](https://coveralls.io/repos/github/floriandejonckheere/metal_archives/badge.svg)](https://coveralls.io/github/floriandejonckheere/metal_archives)
2
2
 
3
3
  ## Installation
4
4
 
@@ -20,20 +20,29 @@ $ bundle install
20
20
 
21
21
  ```ruby
22
22
  MetalArchives.configure do |c|
23
- # Application identity (required)
24
- c.app_name = "My App"
25
- c.app_version = "1.0"
26
- c.app_contact = "support@mymusicapp.com"
23
+ ## Application identity (required)
24
+ c.app_name = 'My App'
25
+ c.app_version = '1.0'
26
+ c.app_contact = 'support@mymusicapp.com'
27
27
 
28
- # Request throttling (optional, overrides defaults)
28
+ ## Request throttling (optional, overrides defaults)
29
29
  c.request_rate = 1
30
30
  c.request_timeout = 3
31
+
32
+ ## Connect additional Faraday middleware
33
+ # c.middleware = [MyMiddleware, MyOtherMiddleware]
31
34
 
32
- # Custom cache size per object class (optional, overrides defaults)
35
+ ## Custom cache size per object class (optional, overrides defaults)
33
36
  c.cache_size = 100
34
-
35
- # Custom logger (optional)
37
+
38
+ ## Metal Archives endpoint (optional, overrides default)
39
+ # c.endpoint = 'http://www.metal-archives.com/'
40
+
41
+ ## Custom logger (optional)
36
42
  c.logger = Logger.new File.new('metal_archives.log')
43
+
44
+ ## Verbose output
45
+ # c.debug = false
37
46
  end
38
47
  ```
39
48
 
@@ -74,6 +83,65 @@ By default when an model (Artist, Band, ...) is created, no data is fetched. Thi
74
83
 
75
84
  Models can be forced to load all data by calling the `:load!` method.
76
85
 
86
+ ## Cache
87
+
88
+ In order not to stress the Metal Archives server, you can quickly set up a local proxy that caches the requests. For NGINX, adjust the following configuration:
89
+
90
+ ```
91
+ # Set cache dir
92
+ proxy_cache_path /var/cache/nginx/metal_archives levels=1:2 keys_zone=metal_archives:10m;
93
+
94
+ # Set cache key to include identifying components
95
+ proxy_cache_key $scheme$proxy_host$request_uri;
96
+
97
+ # Add cache status to log
98
+ log_format cache '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" cs=$upstream_cache_status';
99
+
100
+ server {
101
+ server_name metal-archives.myhost.com;
102
+ listen 443 ssl;
103
+ listen [::]:443 ssl;
104
+
105
+ ssl_certificate /path/to/ssl_certificate.crt;
106
+ ssl_certificate_key /path/to/ssl_certificate_key.key;
107
+
108
+ access_log /var/log/nginx/metal_archives_access.log;
109
+ error_log /var/log/nginx/metal_archives_error.log;
110
+
111
+ # Limit HTTP requests
112
+ limit_req_zone $binary_remote_addr zone=ma_limit_req:10m rate=2r/s;
113
+
114
+ location / {
115
+ proxy_redirect off;
116
+ proxy_set_header Host www.metal-archives.com;
117
+ proxy_set_header X-Forwarded-Host $host;
118
+ proxy_set_header X-Forwarded-Server $host;
119
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
120
+ proxy_set_header X-Real-IP $remote_addr;
121
+
122
+ proxy_pass https://www.metal-archives.com/;
123
+
124
+ limit_req zone=ma_limit_req burst=5;
125
+
126
+ proxy_ignore_headers X-Accel-Expires;
127
+ proxy_ignore_headers Expires;
128
+ proxy_ignore_headers Cache-Control;
129
+ proxy_ignore_headers Set-Cookie;
130
+
131
+ proxy_hide_header Set-Cookie;
132
+ proxy_hide_header Pragma;
133
+
134
+ # Cache valid responses for 30 days
135
+ proxy_cache metal_archives;
136
+ proxy_cache_valid 200 301 302 30d;
137
+ proxy_cache_valid 404 7d;
138
+ expires 30d;
139
+ }
140
+
141
+ add_header X-Cache-Status $upstream_cache_status;
142
+ }
143
+ ```
144
+
77
145
  ## Testing
78
146
  ```
79
147
  $ bundle exec rake test
data/Rakefile CHANGED
@@ -1,14 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rake'
2
4
  require 'rake/testtask'
3
5
 
4
6
  Rake::TestTask.new do |t|
5
- t.libs << "test"
7
+ t.libs << 'test'
6
8
  t.test_files = FileList['test/*/*_test.rb']
7
9
  t.verbose = true
8
10
  end
9
11
 
10
12
  require 'rdoc/task'
11
13
  RDoc::Task.new do |rdoc|
12
- rdoc.main = "README.md"
13
- rdoc.rdoc_files.include("README.md", "lib/**/*.rb")
14
+ rdoc.main = 'README.md'
15
+ rdoc.rdoc_files.include('README.md', 'lib/**/*.rb')
14
16
  end
@@ -1,3 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openssl'
4
+
5
+ require 'metal_archives/middleware/headers'
6
+ require 'metal_archives/middleware/rewrite_endpoint'
7
+
1
8
  require 'metal_archives/version'
2
9
  require 'metal_archives/configuration'
3
10
  require 'metal_archives/error'
@@ -5,6 +12,7 @@ require 'metal_archives/error'
5
12
  require 'metal_archives/utils/range'
6
13
  require 'metal_archives/utils/collection'
7
14
  require 'metal_archives/utils/lru_cache'
15
+ require 'metal_archives/utils/nil_date'
8
16
 
9
17
  require 'metal_archives/models/base_model'
10
18
  require 'metal_archives/models/label'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MetalArchives
2
4
  class << self
3
5
  ##
@@ -5,7 +7,11 @@ module MetalArchives
5
7
  #
6
8
  # Instance of rdoc-ref:MetalArchives::Configuration
7
9
  #
8
- attr_accessor :config
10
+ def config
11
+ raise MetalArchives::Errors::InvalidConfigurationError, 'Gem has not been configured' unless @config
12
+
13
+ @config
14
+ end
9
15
 
10
16
  ##
11
17
  # Configure API options.
@@ -18,11 +24,14 @@ module MetalArchives
18
24
  #
19
25
  def configure
20
26
  raise MetalArchives::Errors::InvalidConfigurationError, 'No configuration block given' unless block_given?
21
- yield MetalArchives.config ||= MetalArchives::Configuration.new
27
+ @config = MetalArchives::Configuration.new
28
+ yield @config
22
29
 
23
- raise MetalArchives::Errors::InvalidConfigurationError, 'app_name has not been configured' unless MetalArchives.config.app_name and not MetalArchives.config.app_name.empty?
24
- raise MetalArchives::Errors::InvalidConfigurationError, 'app_version has not been configured' unless MetalArchives.config.app_version and not MetalArchives.config.app_version.empty?
25
- raise MetalArchives::Errors::InvalidConfigurationError, 'app_contact has not been configured' unless MetalArchives.config.app_contact and not MetalArchives.config.app_contact.empty?
30
+ @config.logger.level = @config.debug ? Logger::DEBUG : Logger::WARN
31
+
32
+ raise MetalArchives::Errors::InvalidConfigurationError, 'app_name has not been configured' unless MetalArchives.config.app_name && !MetalArchives.config.app_name.empty?
33
+ raise MetalArchives::Errors::InvalidConfigurationError, 'app_version has not been configured' unless MetalArchives.config.app_version && !MetalArchives.config.app_version.empty?
34
+ raise MetalArchives::Errors::InvalidConfigurationError, 'app_contact has not been configured' unless MetalArchives.config.app_contact && !MetalArchives.config.app_contact.empty?
26
35
  end
27
36
  end
28
37
 
@@ -46,9 +55,15 @@ module MetalArchives
46
55
  attr_accessor :app_contact
47
56
 
48
57
  ##
49
- # Metal Archives endpoint (defaults to http://www.metal-archives.com/)
58
+ # Override Metal Archives endpoint (defaults to http://www.metal-archives.com/)
50
59
  #
51
60
  attr_accessor :endpoint
61
+ attr_reader :default_endpoint
62
+
63
+ ##
64
+ # Additional Faraday middleware
65
+ #
66
+ attr_accessor :middleware
52
67
 
53
68
  ##
54
69
  # Request throttling rate (in seconds per request per path)
@@ -65,6 +80,11 @@ module MetalArchives
65
80
  #
66
81
  attr_accessor :logger
67
82
 
83
+ ##
84
+ # Verbose output
85
+ #
86
+ attr_accessor :debug
87
+
68
88
  ##
69
89
  # Cache size (per object class)
70
90
  #
@@ -74,10 +94,11 @@ module MetalArchives
74
94
  # Default configuration values
75
95
  #
76
96
  def initialize
77
- @endpoint = 'http://www.metal-archives.com/'
97
+ @default_endpoint = 'https://www.metal-archives.com/'
78
98
  @throttle_rate = 1
79
99
  @throttle_wait = 3
80
100
  @logger = Logger.new STDOUT
101
+ @debug = false
81
102
  @cache_size = 100
82
103
  end
83
104
  end
@@ -1,40 +1,47 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MetalArchives
2
- ##
3
- # MetalArchives gem specific errors
4
- #
5
- module Errors
6
4
  ##
7
- # Generic error
5
+ # MetalArchives gem specific errors
8
6
  #
9
- class Error < StandardError; end
7
+ module Errors
8
+ ##
9
+ # Generic error
10
+ #
11
+ class Error < StandardError; end
10
12
 
11
- ##
12
- # No or invalid ID
13
- #
14
- class InvalidIDError < Error; end
13
+ ##
14
+ # No or invalid ID
15
+ #
16
+ class InvalidIDError < Error; end
15
17
 
16
- ##
17
- # No or invalid configuration
18
- #
19
- class InvalidConfigurationError < Error; end
18
+ ##
19
+ # No or invalid configuration
20
+ #
21
+ class InvalidConfigurationError < Error; end
20
22
 
21
- ##
22
- # Error parsing value
23
- #
24
- class ParserError < Error; end
23
+ ##
24
+ # Error parsing value
25
+ #
26
+ class ParserError < Error; end
25
27
 
26
- ##
27
- # Functionality not implemented (yet)
28
- class NotImplementedError < Error; end
28
+ ##
29
+ # Functionality not implemented (yet)
30
+ class NotImplementedError < Error; end
29
31
 
30
- ##
31
- # Error in backend response
32
- #
33
- class APIError < Error; end
32
+ ##
33
+ # Error in backend response
34
+ #
35
+ class APIError < Error; end
34
36
 
35
- ##
36
- # Error in method argument
37
- #
38
- class ArgumentError < Error; end
39
- end
37
+ ##
38
+ # Error in method argument
39
+ #
40
+ class ArgumentError < Error; end
41
+
42
+ ##
43
+ # Incorrect type
44
+ #
45
+ class TypeError < Error; end
46
+ end
40
47
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'faraday'
2
4
  require 'faraday_throttler'
3
5
 
@@ -7,7 +9,6 @@ module MetalArchives
7
9
  #
8
10
  class HTTPClient # :nodoc:
9
11
  class << self
10
-
11
12
  ##
12
13
  # Retrieve a HTTP resource
13
14
  #
@@ -27,53 +28,31 @@ module MetalArchives
27
28
  end
28
29
 
29
30
  private
30
- ##
31
- # Retrieve a HTTP client
32
- #
33
- #
34
- def client
35
- raise Errors::InvalidConfigurationError, 'Not configured yet' unless MetalArchives.config
36
31
 
37
- @faraday ||= Faraday.new do |f|
38
- f.request :url_encoded # form-encode POST params
39
- f.response :logger, MetalArchives.config.logger
40
-
41
- f.use MetalArchives::Middleware
42
- f.use :throttler,
43
- :rate => MetalArchives.config.request_rate,
44
- :wait => MetalArchives.config.request_timeout,
45
- :logger => MetalArchives.config.logger
32
+ ##
33
+ # Retrieve a HTTP client
34
+ #
35
+ #
36
+ def client
37
+ raise Errors::InvalidConfigurationError, 'Not configured yet' unless MetalArchives.config
46
38
 
47
- f.adapter Faraday.default_adapter
48
- end
49
- end
50
- end
51
- end
39
+ @faraday ||= Faraday.new do |f|
40
+ f.request :url_encoded # form-encode POST params
41
+ f.response :logger, MetalArchives.config.logger
52
42
 
53
- ##
54
- # Faraday middleware
55
- #
56
- class Middleware < Faraday::Middleware # :nodoc:
57
- def call(env)
58
- env[:request_headers].merge!(
59
- 'User-Agent' => user_agent_string,
60
- 'Via' => via_string,
61
- 'Accept' => accept_string
62
- )
63
- @app.call(env)
64
- end
43
+ f.use MetalArchives::Middleware::Headers
44
+ f.use MetalArchives::Middleware::RewriteEndpoint
65
45
 
66
- private
67
- def user_agent_string
68
- "#{MetalArchives.config.app_name}/#{MetalArchives.config.app_version} ( #{MetalArchives.config.app_contact} )"
69
- end
46
+ MetalArchives.config.middleware.each { |m| f.use m } if MetalArchives.config.middleware
70
47
 
71
- def accept_string
72
- 'application/json'
73
- end
48
+ f.use :throttler,
49
+ :rate => MetalArchives.config.request_rate,
50
+ :wait => MetalArchives.config.request_timeout,
51
+ :logger => MetalArchives.config.logger
74
52
 
75
- def via_string
76
- "gem metal_archives/#{VERSION}"
53
+ f.adapter Faraday.default_adapter
54
+ end
77
55
  end
56
+ end
78
57
  end
79
58
  end