metal_archives 2.2.3 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +59 -12
- data/.rspec +1 -0
- data/.rubocop.yml +34 -20
- data/CHANGELOG.md +16 -1
- data/LICENSE.md +17 -4
- data/README.md +37 -29
- data/bin/console +8 -11
- data/config/inflections.rb +7 -0
- data/config/initializers/.keep +0 -0
- data/docker-compose.yml +10 -1
- data/lib/metal_archives.rb +57 -21
- data/lib/metal_archives/cache/base.rb +40 -0
- data/lib/metal_archives/cache/memory.rb +68 -0
- data/lib/metal_archives/cache/null.rb +22 -0
- data/lib/metal_archives/cache/redis.rb +49 -0
- data/lib/metal_archives/collection.rb +3 -5
- data/lib/metal_archives/configuration.rb +28 -21
- data/lib/metal_archives/errors.rb +9 -1
- data/lib/metal_archives/http_client.rb +42 -46
- data/lib/metal_archives/models/artist.rb +55 -26
- data/lib/metal_archives/models/band.rb +43 -36
- data/lib/metal_archives/models/{base_model.rb → base.rb} +57 -50
- data/lib/metal_archives/models/label.rb +7 -8
- data/lib/metal_archives/models/release.rb +21 -18
- data/lib/metal_archives/parsers/artist.rb +41 -36
- data/lib/metal_archives/parsers/band.rb +73 -29
- data/lib/metal_archives/parsers/base.rb +14 -0
- data/lib/metal_archives/parsers/country.rb +21 -0
- data/lib/metal_archives/parsers/date.rb +31 -0
- data/lib/metal_archives/parsers/genre.rb +67 -0
- data/lib/metal_archives/parsers/label.rb +21 -13
- data/lib/metal_archives/parsers/parser.rb +17 -77
- data/lib/metal_archives/parsers/release.rb +29 -18
- data/lib/metal_archives/parsers/year.rb +31 -0
- data/lib/metal_archives/version.rb +3 -3
- data/metal_archives.env.example +7 -4
- data/metal_archives.gemspec +7 -4
- data/nginx/default.conf +2 -2
- metadata +76 -32
- data/.github/workflows/release.yml +0 -69
- data/.rubocop_todo.yml +0 -92
- data/lib/metal_archives/lru_cache.rb +0 -61
- data/lib/metal_archives/middleware/cache_check.rb +0 -18
- data/lib/metal_archives/middleware/encoding.rb +0 -16
- data/lib/metal_archives/middleware/headers.rb +0 -38
- data/lib/metal_archives/middleware/rewrite_endpoint.rb +0 -38
- data/lib/metal_archives/nil_date.rb +0 -91
- data/lib/metal_archives/range.rb +0 -69
@@ -8,7 +8,7 @@ module MetalArchives
|
|
8
8
|
##
|
9
9
|
# Represents a single performer (but not a solo artist)
|
10
10
|
#
|
11
|
-
class Artist <
|
11
|
+
class Artist < Base
|
12
12
|
##
|
13
13
|
# :attr_reader: id
|
14
14
|
#
|
@@ -63,24 +63,24 @@ module MetalArchives
|
|
63
63
|
##
|
64
64
|
# :attr_reader: date_of_birth
|
65
65
|
#
|
66
|
-
# Returns rdoc-ref:
|
66
|
+
# Returns rdoc-ref:Date
|
67
67
|
#
|
68
68
|
# [Raises]
|
69
69
|
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
70
70
|
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
71
71
|
#
|
72
|
-
property :date_of_birth, type:
|
72
|
+
property :date_of_birth, type: Date
|
73
73
|
|
74
74
|
##
|
75
75
|
# :attr_reader: date_of_death
|
76
76
|
#
|
77
|
-
# Returns rdoc-ref:
|
77
|
+
# Returns rdoc-ref:Date
|
78
78
|
#
|
79
79
|
# [Raises]
|
80
80
|
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
81
81
|
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
82
82
|
#
|
83
|
-
property :date_of_death, type:
|
83
|
+
property :date_of_death, type: Date
|
84
84
|
|
85
85
|
##
|
86
86
|
# :attr_reader: cause_of_death
|
@@ -102,7 +102,7 @@ module MetalArchives
|
|
102
102
|
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
103
103
|
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
104
104
|
#
|
105
|
-
enum :gender, values:
|
105
|
+
enum :gender, values: [:male, :female]
|
106
106
|
|
107
107
|
##
|
108
108
|
# :attr_reader: biography
|
@@ -165,7 +165,7 @@ module MetalArchives
|
|
165
165
|
# [+bands+]
|
166
166
|
# - +:band+: rdoc-ref:Band
|
167
167
|
# - +:active+: Boolean
|
168
|
-
# - +:
|
168
|
+
# - +:years_active+: +Array+ of rdoc-ref:Range containing +Integer+
|
169
169
|
# - +:role+: +String+
|
170
170
|
#
|
171
171
|
property :bands, type: Hash, multiple: true
|
@@ -173,6 +173,41 @@ module MetalArchives
|
|
173
173
|
# TODO: guest/session bands
|
174
174
|
# TODO: misc bands
|
175
175
|
|
176
|
+
##
|
177
|
+
# Serialize to hash
|
178
|
+
#
|
179
|
+
def to_h
|
180
|
+
{
|
181
|
+
type: "artist",
|
182
|
+
id: id,
|
183
|
+
name: name,
|
184
|
+
aliases: aliases || [],
|
185
|
+
country: country&.alpha3,
|
186
|
+
location: location,
|
187
|
+
date_of_birth: date_of_birth&.iso8601,
|
188
|
+
date_of_death: date_of_death&.iso8601,
|
189
|
+
cause_of_death: cause_of_death,
|
190
|
+
gender: gender,
|
191
|
+
biography: biography,
|
192
|
+
trivia: trivia,
|
193
|
+
photo: photo,
|
194
|
+
links: links || [],
|
195
|
+
bands: bands || [],
|
196
|
+
}
|
197
|
+
end
|
198
|
+
|
199
|
+
##
|
200
|
+
# Deserialize from hash
|
201
|
+
#
|
202
|
+
def self.from_h(hash)
|
203
|
+
return unless hash.fetch(:type) == "artist"
|
204
|
+
|
205
|
+
new(hash.slice(:id, :name, :aliases, :location, :cause_of_death, :gender, :biography, :trivial, :photo, :links, :bands))
|
206
|
+
.tap { |m| m.country = ISO3166::Country[hash[:country]] }
|
207
|
+
.tap { |m| m.date_of_birth = Date.parse(hash[:date_of_birth]) if hash[:date_of_birth] }
|
208
|
+
.tap { |m| m.date_of_death = Date.parse(hash[:date_of_death]) if hash[:date_of_death] }
|
209
|
+
end
|
210
|
+
|
176
211
|
protected
|
177
212
|
|
178
213
|
##
|
@@ -184,28 +219,24 @@ module MetalArchives
|
|
184
219
|
#
|
185
220
|
def assemble # :nodoc:
|
186
221
|
## Base attributes
|
187
|
-
|
188
|
-
response = HTTPClient.get url
|
222
|
+
response = MetalArchives.http.get "/artist/view/id/#{id}"
|
189
223
|
|
190
|
-
properties = Parsers::Artist.parse_html response.
|
224
|
+
properties = Parsers::Artist.parse_html response.to_s
|
191
225
|
|
192
226
|
## Biography
|
193
|
-
|
194
|
-
response = HTTPClient.get url
|
227
|
+
response = MetalArchives.http.get "/artist/read-more/id/#{id}/field/biography"
|
195
228
|
|
196
|
-
properties[:biography] = response.
|
229
|
+
properties[:biography] = response.to_s
|
197
230
|
|
198
231
|
## Trivia
|
199
|
-
|
200
|
-
response = HTTPClient.get url
|
232
|
+
response = MetalArchives.http.get "/artist/read-more/id/#{id}/field/trivia"
|
201
233
|
|
202
|
-
properties[:trivia] = response.
|
234
|
+
properties[:trivia] = response.to_s
|
203
235
|
|
204
236
|
## Related links
|
205
|
-
|
206
|
-
response = HTTPClient.get url
|
237
|
+
response = MetalArchives.http.get "/link/ajax-list/type/person/id/#{id}"
|
207
238
|
|
208
|
-
properties[:links] = Parsers::Artist.parse_links_html response.
|
239
|
+
properties[:links] = Parsers::Artist.parse_links_html response.to_s
|
209
240
|
|
210
241
|
properties
|
211
242
|
end
|
@@ -220,7 +251,7 @@ module MetalArchives
|
|
220
251
|
# +Integer+
|
221
252
|
#
|
222
253
|
def find(id)
|
223
|
-
return cache[id] if cache.include? id
|
254
|
+
return MetalArchives.cache[cache(id)] if MetalArchives.cache.include? cache(id)
|
224
255
|
|
225
256
|
Artist.new id: id
|
226
257
|
end
|
@@ -262,11 +293,10 @@ module MetalArchives
|
|
262
293
|
def find_by(query)
|
263
294
|
raise MetalArchives::Errors::ArgumentError unless query.include? :name
|
264
295
|
|
265
|
-
url = "#{MetalArchives.config.default_endpoint}search/ajax-artist-search/"
|
266
296
|
params = Parsers::Artist.map_params query
|
267
297
|
|
268
|
-
response =
|
269
|
-
json = JSON.parse response.
|
298
|
+
response = MetalArchives.http.get "/search/ajax-artist-search/", params
|
299
|
+
json = JSON.parse response.to_s
|
270
300
|
|
271
301
|
return nil if json["aaData"].empty?
|
272
302
|
|
@@ -314,7 +344,6 @@ module MetalArchives
|
|
314
344
|
def search(name)
|
315
345
|
raise MetalArchives::Errors::ArgumentError unless name.is_a? String
|
316
346
|
|
317
|
-
url = "#{MetalArchives.config.default_endpoint}search/ajax-artist-search/"
|
318
347
|
query = { name: name }
|
319
348
|
|
320
349
|
params = Parsers::Artist.map_params query
|
@@ -325,8 +354,8 @@ module MetalArchives
|
|
325
354
|
if @max_items && @start >= @max_items
|
326
355
|
[]
|
327
356
|
else
|
328
|
-
response =
|
329
|
-
json = JSON.parse response.
|
357
|
+
response = MetalArchives.http.get "/search/ajax-artist-search/", params.merge(iDisplayStart: @start)
|
358
|
+
json = JSON.parse response.to_s
|
330
359
|
|
331
360
|
@max_items = json["iTotalRecords"]
|
332
361
|
|
@@ -8,7 +8,7 @@ module MetalArchives
|
|
8
8
|
##
|
9
9
|
# Represents an band (person or group)
|
10
10
|
#
|
11
|
-
class Band <
|
11
|
+
class Band < Base
|
12
12
|
##
|
13
13
|
# :attr_reader: id
|
14
14
|
#
|
@@ -63,24 +63,24 @@ module MetalArchives
|
|
63
63
|
##
|
64
64
|
# :attr_reader: date_formed
|
65
65
|
#
|
66
|
-
# Returns rdoc-ref:
|
66
|
+
# Returns rdoc-ref:Date
|
67
67
|
#
|
68
68
|
# [Raises]
|
69
69
|
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
70
70
|
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
71
71
|
#
|
72
|
-
property :date_formed, type:
|
72
|
+
property :date_formed, type: Date
|
73
73
|
|
74
74
|
##
|
75
|
-
# :attr_reader:
|
75
|
+
# :attr_reader: years_active
|
76
76
|
#
|
77
|
-
# Returns +Array+ of rdoc-ref:Range containing
|
77
|
+
# Returns +Array+ of rdoc-ref:Range containing +Integer+
|
78
78
|
#
|
79
79
|
# [Raises]
|
80
80
|
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
81
81
|
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
82
82
|
#
|
83
|
-
property :
|
83
|
+
property :years_active, type: Range, multiple: true
|
84
84
|
|
85
85
|
##
|
86
86
|
# :attr_reader: genres
|
@@ -113,7 +113,7 @@ module MetalArchives
|
|
113
113
|
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
114
114
|
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
115
115
|
#
|
116
|
-
property :label, type:
|
116
|
+
property :label, type: Label
|
117
117
|
|
118
118
|
##
|
119
119
|
# :attr_reader: independent
|
@@ -146,7 +146,7 @@ module MetalArchives
|
|
146
146
|
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
147
147
|
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
148
148
|
#
|
149
|
-
enum :status, values:
|
149
|
+
enum :status, values: [:active, :split_up, :on_hold, :unknown, :changed_name, :disputed]
|
150
150
|
|
151
151
|
##
|
152
152
|
# :attr_reader: releases
|
@@ -157,9 +157,24 @@ module MetalArchives
|
|
157
157
|
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
158
158
|
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
159
159
|
#
|
160
|
-
property :releases, type:
|
160
|
+
property :releases, type: Release, multiple: true
|
161
161
|
|
162
|
-
|
162
|
+
##
|
163
|
+
# :attr_reader: members
|
164
|
+
#
|
165
|
+
# Returns +Array+ of +Hash+ containing the following keys
|
166
|
+
#
|
167
|
+
# [Raises]
|
168
|
+
# - rdoc-ref:MetalArchives::Errors::InvalidIDError when no or invalid id
|
169
|
+
# - rdoc-ref:MetalArchives::Errors::APIError when receiving a status code >= 400 (except 404)
|
170
|
+
#
|
171
|
+
# [+members+]
|
172
|
+
# - +:artist+: rdoc-ref:Artist
|
173
|
+
# - +:current+: Boolean
|
174
|
+
# - +:years_active+: +Array+ of rdoc-ref:Range containing +Integer+
|
175
|
+
# - +:role+: +String+
|
176
|
+
#
|
177
|
+
property :members, type: Artist, multiple: true
|
163
178
|
|
164
179
|
##
|
165
180
|
# :attr_reader: similar
|
@@ -225,34 +240,29 @@ module MetalArchives
|
|
225
240
|
#
|
226
241
|
def assemble # :nodoc:
|
227
242
|
## Base attributes
|
228
|
-
|
229
|
-
response = HTTPClient.get url
|
243
|
+
response = MetalArchives.http.get "/band/view/id/#{id}"
|
230
244
|
|
231
|
-
properties = Parsers::Band.parse_html response.
|
245
|
+
properties = Parsers::Band.parse_html response.to_s
|
232
246
|
|
233
247
|
## Comment
|
234
|
-
|
235
|
-
response = HTTPClient.get url
|
248
|
+
response = MetalArchives.http.get "/band/read-more/id/#{id}"
|
236
249
|
|
237
|
-
properties[:comment] = response.
|
250
|
+
properties[:comment] = response.to_s
|
238
251
|
|
239
252
|
## Similar artists
|
240
|
-
|
241
|
-
response = HTTPClient.get url
|
253
|
+
response = MetalArchives.http.get "/band/ajax-recommendations/id/#{id}"
|
242
254
|
|
243
|
-
properties[:similar] = Parsers::Band.parse_similar_bands_html response.
|
255
|
+
properties[:similar] = Parsers::Band.parse_similar_bands_html response.to_s
|
244
256
|
|
245
257
|
## Related links
|
246
|
-
|
247
|
-
response = HTTPClient.get url
|
258
|
+
response = MetalArchives.http.get "/link/ajax-list/type/band/id/#{id}"
|
248
259
|
|
249
|
-
properties[:links] = Parsers::Band.parse_related_links_html response.
|
260
|
+
properties[:links] = Parsers::Band.parse_related_links_html response.to_s
|
250
261
|
|
251
262
|
## Releases
|
252
|
-
|
253
|
-
response = HTTPClient.get url
|
263
|
+
response = MetalArchives.http.get "/band/discography/id/#{id}/tab/all"
|
254
264
|
|
255
|
-
properties[:releases] = Parsers::Band.parse_releases_html response.
|
265
|
+
properties[:releases] = Parsers::Band.parse_releases_html response.to_s
|
256
266
|
|
257
267
|
properties
|
258
268
|
end
|
@@ -267,7 +277,7 @@ module MetalArchives
|
|
267
277
|
# +Integer+
|
268
278
|
#
|
269
279
|
def find(id)
|
270
|
-
return cache[id] if cache.include? id
|
280
|
+
return MetalArchives.cache[cache(id)] if MetalArchives.cache.include? cache(id)
|
271
281
|
|
272
282
|
Band.new id: id
|
273
283
|
end
|
@@ -309,7 +319,7 @@ module MetalArchives
|
|
309
319
|
# - +:exact+: +Boolean+
|
310
320
|
# - +:genre+: +String+
|
311
321
|
# - +:country+: +ISO3166::Country+
|
312
|
-
# - +:year_formation+: rdoc-ref:Range containing rdoc-ref:
|
322
|
+
# - +:year_formation+: rdoc-ref:Range containing rdoc-ref:Date
|
313
323
|
# - +:comment+: +String+
|
314
324
|
# - +:status+: see rdoc-ref:Band.status
|
315
325
|
# - +:lyrical_themes+: +String+
|
@@ -318,11 +328,10 @@ module MetalArchives
|
|
318
328
|
# - +:independent+: boolean
|
319
329
|
#
|
320
330
|
def find_by(query)
|
321
|
-
url = "#{MetalArchives.config.default_endpoint}search/ajax-advanced/searching/bands"
|
322
331
|
params = Parsers::Band.map_params query
|
323
332
|
|
324
|
-
response =
|
325
|
-
json = JSON.parse response.
|
333
|
+
response = MetalArchives.http.get "/search/ajax-advanced/searching/bands", params
|
334
|
+
json = JSON.parse response.to_s
|
326
335
|
|
327
336
|
return nil if json["aaData"].empty?
|
328
337
|
|
@@ -349,7 +358,7 @@ module MetalArchives
|
|
349
358
|
# - +:exact+: +Boolean+
|
350
359
|
# - +:genre+: +String+
|
351
360
|
# - +:country+: +ISO3166::Country+
|
352
|
-
# - +:year_formation+: rdoc-ref:Range containing rdoc-ref:
|
361
|
+
# - +:year_formation+: rdoc-ref:Range containing rdoc-ref:Date
|
353
362
|
# - +:comment+: +String+
|
354
363
|
# - +:status+: see rdoc-ref:Band.status
|
355
364
|
# - +:lyrical_themes+: +String+
|
@@ -381,7 +390,7 @@ module MetalArchives
|
|
381
390
|
# - +:exact+: +Boolean+
|
382
391
|
# - +:genre+: +String+
|
383
392
|
# - +:country+: +ISO3166::Country+
|
384
|
-
# - +:year_formation+: rdoc-ref:Range containing rdoc-ref:
|
393
|
+
# - +:year_formation+: rdoc-ref:Range containing rdoc-ref:Date
|
385
394
|
# - +:comment+: +String+
|
386
395
|
# - +:status+: see rdoc-ref:Band.status
|
387
396
|
# - +:lyrical_themes+: +String+
|
@@ -390,8 +399,6 @@ module MetalArchives
|
|
390
399
|
# - +:independent+: boolean
|
391
400
|
#
|
392
401
|
def search_by(query)
|
393
|
-
url = "#{MetalArchives.config.default_endpoint}search/ajax-advanced/searching/bands"
|
394
|
-
|
395
402
|
params = Parsers::Band.map_params query
|
396
403
|
|
397
404
|
l = lambda do
|
@@ -400,8 +407,8 @@ module MetalArchives
|
|
400
407
|
if @max_items && @start >= @max_items
|
401
408
|
[]
|
402
409
|
else
|
403
|
-
response =
|
404
|
-
json = JSON.parse response.
|
410
|
+
response = MetalArchives.http.get "/search/ajax-advanced/searching/bands", params.merge(iDisplayStart: @start)
|
411
|
+
json = JSON.parse response.to_s
|
405
412
|
|
406
413
|
@max_items = json["iTotalRecords"]
|
407
414
|
|
@@ -4,48 +4,49 @@ module MetalArchives
|
|
4
4
|
##
|
5
5
|
# Abstract model class
|
6
6
|
#
|
7
|
-
class
|
7
|
+
class Base
|
8
8
|
##
|
9
9
|
# Generic shallow copy constructor
|
10
10
|
#
|
11
|
-
def initialize(
|
12
|
-
raise Errors::NotImplementedError, "no :id property in model" unless respond_to? :id
|
11
|
+
def initialize(attributes = {})
|
12
|
+
raise Errors::NotImplementedError, "no :id property in model" unless respond_to? :id
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
set(**attributes)
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Set properties
|
19
|
+
#
|
20
|
+
def set(**attributes)
|
21
|
+
attributes.each { |key, value| instance_variable_set(:"@#{key}", value) }
|
17
22
|
end
|
18
23
|
|
19
24
|
##
|
20
25
|
# Returns true if two objects have the same type and id
|
21
26
|
#
|
22
|
-
def ==(
|
23
|
-
|
27
|
+
def ==(other)
|
28
|
+
other.is_a?(self.class) &&
|
29
|
+
id == other.id
|
24
30
|
end
|
25
31
|
|
26
32
|
##
|
27
33
|
# Fetch, parse and load the data
|
28
34
|
#
|
29
35
|
# [Raises]
|
30
|
-
# - rdoc-ref:
|
31
|
-
# - rdoc-ref:
|
36
|
+
# - rdoc-ref:Errors::InvalidIDError when no id
|
37
|
+
# - rdoc-ref:Errors::APIError when receiving a status code >= 400 (except 404)
|
32
38
|
#
|
33
39
|
def load!
|
34
40
|
raise Errors::InvalidIDError, "no id present" unless id
|
35
41
|
|
36
42
|
# Use constructor to set attributes
|
37
|
-
|
38
|
-
|
39
|
-
# Set empty properties to nil
|
40
|
-
self.class.properties.each do |prop|
|
41
|
-
instance_variable_set("@#{prop}", nil) unless instance_variable_defined? "@#{prop}"
|
42
|
-
end
|
43
|
+
set(**assemble)
|
43
44
|
|
44
45
|
@loaded = true
|
45
|
-
self.class.cache
|
46
|
+
MetalArchives.cache[self.class.cache(id)] = self
|
46
47
|
rescue StandardError => e
|
47
48
|
# Don't cache invalid requests
|
48
|
-
self.class.cache
|
49
|
+
MetalArchives.cache.delete self.class.cache(id)
|
49
50
|
raise e
|
50
51
|
end
|
51
52
|
|
@@ -53,14 +54,21 @@ module MetalArchives
|
|
53
54
|
# Whether or not the object is currently loaded
|
54
55
|
#
|
55
56
|
def loaded?
|
56
|
-
|
57
|
+
@loaded ||= false
|
57
58
|
end
|
58
59
|
|
59
60
|
##
|
60
61
|
# Whether or not the object is currently cached
|
61
62
|
#
|
62
63
|
def cached?
|
63
|
-
loaded? &&
|
64
|
+
loaded? && MetalArchives.cache.include?(self.class.cache(id))
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# String representation
|
69
|
+
#
|
70
|
+
def inspect
|
71
|
+
"#<#{self.class.name} @id=#{@id} @name=\"#{@name}\">"
|
64
72
|
end
|
65
73
|
|
66
74
|
protected
|
@@ -71,8 +79,8 @@ module MetalArchives
|
|
71
79
|
# Override this method
|
72
80
|
#
|
73
81
|
# [Raises]
|
74
|
-
# - rdoc-ref:
|
75
|
-
# - rdoc-ref:
|
82
|
+
# - rdoc-ref:Errors::InvalidIDError when no or invalid id
|
83
|
+
# - rdoc-ref:Errors::APIError when receiving a status code >= 400 (except 404)
|
76
84
|
#
|
77
85
|
def assemble
|
78
86
|
raise Errors::NotImplementedError, "method :assemble not implemented"
|
@@ -80,15 +88,17 @@ module MetalArchives
|
|
80
88
|
|
81
89
|
class << self
|
82
90
|
##
|
83
|
-
#
|
91
|
+
# Declared properties
|
84
92
|
#
|
85
|
-
|
93
|
+
def properties
|
94
|
+
@properties ||= {}
|
95
|
+
end
|
86
96
|
|
87
97
|
##
|
88
|
-
#
|
98
|
+
# Generate cache key for id
|
89
99
|
#
|
90
|
-
def cache
|
91
|
-
|
100
|
+
def cache(id)
|
101
|
+
"#{self.class.name}//#{id}"
|
92
102
|
end
|
93
103
|
|
94
104
|
protected
|
@@ -110,42 +120,38 @@ module MetalArchives
|
|
110
120
|
# turns it into an +Array+ of +type+)
|
111
121
|
#
|
112
122
|
def property(name, opts = {})
|
113
|
-
|
123
|
+
properties[name] = opts
|
114
124
|
|
115
125
|
# property
|
116
126
|
define_method(name) do
|
117
|
-
|
118
|
-
|
127
|
+
# Load only when not loaded or id property
|
128
|
+
load! unless loaded? || name == :id
|
129
|
+
|
130
|
+
instance_variable_get(:"@#{name}")
|
119
131
|
end
|
120
132
|
|
121
133
|
# property?
|
122
134
|
define_method("#{name}?") do
|
123
|
-
|
124
|
-
|
125
|
-
property = instance_variable_get("@#{name}")
|
126
|
-
property.respond_to?(:empty?) ? !property.empty? : !property.nil?
|
135
|
+
send(name).present?
|
127
136
|
end
|
128
137
|
|
129
138
|
# property=
|
130
139
|
define_method("#{name}=") do |value|
|
131
|
-
if value.nil?
|
132
|
-
instance_variable_set "@#{name}", value
|
133
|
-
return
|
134
|
-
end
|
140
|
+
return instance_variable_set(:"@#{name}", value) if value.nil?
|
135
141
|
|
136
142
|
# Check value type
|
137
143
|
type = opts[:type] || String
|
138
144
|
if opts[:multiple]
|
139
|
-
raise
|
145
|
+
raise Errors::TypeError, "invalid type #{value.class}, must be Array for #{name}" unless value.is_a? Array
|
140
146
|
|
141
147
|
value.each do |val|
|
142
|
-
raise
|
148
|
+
raise Errors::TypeError, "invalid type #{val.class}, must be #{type} for #{name}" unless val.is_a? type
|
143
149
|
end
|
144
150
|
else
|
145
|
-
raise
|
151
|
+
raise Errors::TypeError, "invalid type #{value.class}, must be #{type} for #{name}" unless value.is_a? type
|
146
152
|
end
|
147
153
|
|
148
|
-
instance_variable_set
|
154
|
+
instance_variable_set(:"@#{name}", value)
|
149
155
|
end
|
150
156
|
end
|
151
157
|
|
@@ -166,19 +172,20 @@ module MetalArchives
|
|
166
172
|
def enum(name, opts)
|
167
173
|
raise ArgumentError, "opts[:values] is required" unless opts && opts[:values]
|
168
174
|
|
169
|
-
|
175
|
+
properties[name] = opts
|
170
176
|
|
171
177
|
# property
|
172
178
|
define_method(name) do
|
173
|
-
load! unless loaded?
|
174
|
-
|
179
|
+
load! unless loaded?
|
180
|
+
|
181
|
+
instance_variable_get(:"@#{name}")
|
175
182
|
end
|
176
183
|
|
177
184
|
# property?
|
178
185
|
define_method("#{name}?") do
|
179
186
|
load! unless loaded? && instance_variable_defined?("@#{name}")
|
180
187
|
|
181
|
-
property = instance_variable_get("@#{name}")
|
188
|
+
property = instance_variable_get(:"@#{name}")
|
182
189
|
property.respond_to?(:empty?) ? !property.empty? : !property.nil?
|
183
190
|
end
|
184
191
|
|
@@ -186,16 +193,16 @@ module MetalArchives
|
|
186
193
|
define_method("#{name}=") do |value|
|
187
194
|
# Check enum type
|
188
195
|
if opts[:multiple]
|
189
|
-
raise
|
196
|
+
raise Errors::TypeError, "invalid enum value #{value}, must be Array for #{name}" unless value.is_a? Array
|
190
197
|
|
191
198
|
value.each do |val|
|
192
|
-
raise
|
199
|
+
raise Errors::TypeError, "invalid enum value #{val} for #{name}" unless opts[:values].include? val
|
193
200
|
end
|
194
201
|
else
|
195
|
-
raise
|
202
|
+
raise Errors::TypeError, "invalid enum value #{value} for #{name}" unless opts[:values].include? value
|
196
203
|
end
|
197
204
|
|
198
|
-
instance_variable_set
|
205
|
+
instance_variable_set(:"@#{name}", value)
|
199
206
|
end
|
200
207
|
end
|
201
208
|
|