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.
- 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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9c1527cbe8ea9df768ea3112b958fbba43f29dd0
|
4
|
+
data.tar.gz: 82971bd30252efb8e77badb9dfe10c71fb86a585
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 64fb61f7acd105d6aa93f005cccdc1d246de4ac7b9a2fc4f944c7a3ff729698eaedd42faee4228f25549f33beedef1f5d34d3834953abe59054f16161b4dcea0
|
7
|
+
data.tar.gz: e57bc2994341940aa33f283ae028ca3cb7a51f1e634eee3041c66d3d75ff0d765ee93e87cf30d394a6cc9ade61d8458bdab08fb5e4bc5dd5d45ec146fe43d38b
|
data/.gitignore
CHANGED
@@ -1,12 +1,64 @@
|
|
1
|
-
|
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
|
-
|
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
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/{LICENSE → LICENSE.md}
RENAMED
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
|
-
|
24
|
-
c.app_name =
|
25
|
-
c.app_version =
|
26
|
-
c.app_contact =
|
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
|
-
|
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
|
-
|
35
|
+
## Custom cache size per object class (optional, overrides defaults)
|
33
36
|
c.cache_size = 100
|
34
|
-
|
35
|
-
|
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 <<
|
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 =
|
13
|
-
rdoc.rdoc_files.include(
|
14
|
+
rdoc.main = 'README.md'
|
15
|
+
rdoc.rdoc_files.include('README.md', 'lib/**/*.rb')
|
14
16
|
end
|
data/lib/metal_archives.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
27
|
+
@config = MetalArchives::Configuration.new
|
28
|
+
yield @config
|
22
29
|
|
23
|
-
|
24
|
-
|
25
|
-
raise MetalArchives::Errors::InvalidConfigurationError, '
|
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
|
-
@
|
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
|
data/lib/metal_archives/error.rb
CHANGED
@@ -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
|
-
#
|
5
|
+
# MetalArchives gem specific errors
|
8
6
|
#
|
9
|
-
|
7
|
+
module Errors
|
8
|
+
##
|
9
|
+
# Generic error
|
10
|
+
#
|
11
|
+
class Error < StandardError; end
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
##
|
14
|
+
# No or invalid ID
|
15
|
+
#
|
16
|
+
class InvalidIDError < Error; end
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
##
|
19
|
+
# No or invalid configuration
|
20
|
+
#
|
21
|
+
class InvalidConfigurationError < Error; end
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
23
|
+
##
|
24
|
+
# Error parsing value
|
25
|
+
#
|
26
|
+
class ParserError < Error; end
|
25
27
|
|
26
|
-
|
27
|
-
|
28
|
-
|
28
|
+
##
|
29
|
+
# Functionality not implemented (yet)
|
30
|
+
class NotImplementedError < Error; end
|
29
31
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
##
|
33
|
+
# Error in backend response
|
34
|
+
#
|
35
|
+
class APIError < Error; end
|
34
36
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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
|
-
|
48
|
-
|
49
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
72
|
-
|
73
|
-
|
48
|
+
f.use :throttler,
|
49
|
+
:rate => MetalArchives.config.request_rate,
|
50
|
+
:wait => MetalArchives.config.request_timeout,
|
51
|
+
:logger => MetalArchives.config.logger
|
74
52
|
|
75
|
-
|
76
|
-
|
53
|
+
f.adapter Faraday.default_adapter
|
54
|
+
end
|
77
55
|
end
|
56
|
+
end
|
78
57
|
end
|
79
58
|
end
|