rbrainz 0.4.2 → 0.5.0

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 (118) hide show
  1. data/CHANGES +13 -1
  2. data/LICENSE +1 -1
  3. data/README +2 -2
  4. data/Rakefile +2 -2
  5. data/TODO +9 -2
  6. data/doc/README.rdoc +5 -5
  7. data/examples/getartist.rb +3 -2
  8. data/examples/getlabel.rb +3 -2
  9. data/examples/getrelease.rb +5 -2
  10. data/examples/getreleasegroup.rb +53 -0
  11. data/examples/gettrack.rb +3 -2
  12. data/examples/getuser.rb +2 -1
  13. data/examples/rate.rb +44 -0
  14. data/examples/searchartists.rb +3 -2
  15. data/examples/searchcdstubs.rb +41 -0
  16. data/examples/searchlabels.rb +3 -2
  17. data/examples/searchreleasegroups.rb +36 -0
  18. data/examples/searchreleases.rb +6 -4
  19. data/examples/searchtracks.rb +3 -2
  20. data/examples/submit_isrcs.rb +52 -0
  21. data/examples/tag.rb +3 -2
  22. data/lib/rbrainz.rb +2 -1
  23. data/lib/rbrainz/core_ext.rb +2 -1
  24. data/lib/rbrainz/core_ext/mbid.rb +2 -1
  25. data/lib/rbrainz/core_ext/net_http_digest.rb +3 -2
  26. data/lib/rbrainz/core_ext/range.rb +3 -2
  27. data/lib/rbrainz/core_ext/range/equality.rb +2 -1
  28. data/lib/rbrainz/data/countrynames.rb +6 -3
  29. data/lib/rbrainz/data/languagenames.rb +3 -2
  30. data/lib/rbrainz/data/releasetypenames.rb +3 -2
  31. data/lib/rbrainz/data/scriptnames.rb +3 -2
  32. data/lib/rbrainz/model.rb +3 -2
  33. data/lib/rbrainz/model/alias.rb +3 -2
  34. data/lib/rbrainz/model/artist.rb +11 -3
  35. data/lib/rbrainz/model/collection.rb +3 -2
  36. data/lib/rbrainz/model/default_factory.rb +18 -6
  37. data/lib/rbrainz/model/disc.rb +3 -2
  38. data/lib/rbrainz/model/entity.rb +2 -102
  39. data/lib/rbrainz/model/incomplete_date.rb +3 -2
  40. data/lib/rbrainz/model/individual.rb +11 -2
  41. data/lib/rbrainz/model/isrc.rb +100 -0
  42. data/lib/rbrainz/model/label.rb +5 -2
  43. data/lib/rbrainz/model/mbid.rb +28 -9
  44. data/lib/rbrainz/model/rateable.rb +34 -0
  45. data/lib/rbrainz/model/rating.rb +56 -0
  46. data/lib/rbrainz/model/relateable.rb +118 -0
  47. data/lib/rbrainz/model/relation.rb +2 -1
  48. data/lib/rbrainz/model/release.rb +17 -3
  49. data/lib/rbrainz/model/release_event.rb +3 -2
  50. data/lib/rbrainz/model/release_group.rb +97 -0
  51. data/lib/rbrainz/model/scored_collection.rb +3 -2
  52. data/lib/rbrainz/model/tag.rb +5 -4
  53. data/lib/rbrainz/model/taggable.rb +27 -0
  54. data/lib/rbrainz/model/track.rb +15 -2
  55. data/lib/rbrainz/model/user.rb +3 -2
  56. data/lib/rbrainz/utils.rb +2 -1
  57. data/lib/rbrainz/utils/data.rb +3 -2
  58. data/lib/rbrainz/utils/helper.rb +8 -2
  59. data/lib/rbrainz/version.rb +3 -2
  60. data/lib/rbrainz/webservice.rb +12 -7
  61. data/lib/rbrainz/webservice/filter.rb +53 -4
  62. data/lib/rbrainz/webservice/includes.rb +72 -11
  63. data/lib/rbrainz/webservice/mbxml.rb +129 -67
  64. data/lib/rbrainz/webservice/query.rb +156 -16
  65. data/lib/rbrainz/webservice/webservice.rb +104 -116
  66. data/test/lib/mock_webservice.rb +9 -2
  67. data/test/lib/test_entity.rb +2 -97
  68. data/test/lib/test_factory.rb +9 -1
  69. data/test/lib/test_rateable.rb +31 -0
  70. data/test/lib/test_relateable.rb +103 -0
  71. data/test/lib/test_taggable.rb +36 -0
  72. data/test/lib/testing_helper.rb +17 -2
  73. data/test/test-data/invalid/artist/ratings_1.xml +6 -0
  74. data/test/test-data/invalid/artist/ratings_2.xml +6 -0
  75. data/test/test-data/valid/artist/Tchaikovsky-2.xml +6 -0
  76. data/test/test-data/valid/label/Atlantic_Records_3.xml +6 -0
  77. data/test/test-data/valid/release-group/The_Cure_1.xml +36 -0
  78. data/test/test-data/valid/release/Highway_61_Revisited_2.xml +6 -0
  79. data/test/test-data/valid/track/Silent_All_These_Years_4.xml +3 -0
  80. data/test/test-data/valid/track/Silent_All_These_Years_6.xml +8 -0
  81. data/test/test_alias.rb +2 -1
  82. data/test/test_artist.rb +24 -2
  83. data/test/test_artist_filter.rb +2 -1
  84. data/test/test_artist_includes.rb +13 -3
  85. data/test/test_collection.rb +3 -2
  86. data/test/test_default_factory.rb +8 -1
  87. data/test/test_disc.rb +2 -1
  88. data/test/test_incomplete_date.rb +2 -1
  89. data/test/test_isrc.rb +87 -0
  90. data/test/test_label.rb +8 -1
  91. data/test/test_label_filter.rb +2 -1
  92. data/test/test_label_includes.rb +10 -3
  93. data/test/test_mbid.rb +2 -1
  94. data/test/test_mbxml.rb +93 -2
  95. data/test/test_query.rb +68 -5
  96. data/test/test_range_equality.rb +2 -1
  97. data/test/test_rating.rb +46 -0
  98. data/test/test_relation.rb +2 -1
  99. data/test/test_release.rb +37 -2
  100. data/test/test_release_event.rb +2 -1
  101. data/test/test_release_filter.rb +15 -2
  102. data/test/test_release_group.rb +104 -0
  103. data/test/test_release_group_filter.rb +61 -0
  104. data/test/test_release_group_includes.rb +46 -0
  105. data/test/test_release_includes.rb +16 -3
  106. data/test/test_scored_collection.rb +3 -2
  107. data/test/test_tag.rb +2 -1
  108. data/test/test_track.rb +28 -1
  109. data/test/test_track_filter.rb +2 -1
  110. data/test/test_track_includes.rb +13 -3
  111. data/test/test_utils.rb +2 -1
  112. data/test/test_webservice.rb +11 -1
  113. metadata +38 -20
  114. data/debian/changelog +0 -11
  115. data/debian/compat +0 -1
  116. data/debian/control +0 -13
  117. data/debian/copyright +0 -25
  118. data/debian/rules +0 -48
@@ -1,4 +1,5 @@
1
- # $Id: includes.rb 203 2008-03-17 11:00:15Z phw $
1
+ # -*- coding: utf-8 -*-
2
+ # $Id: includes.rb 254 2009-05-13 20:04:36Z phw $
2
3
  #
3
4
  # Author:: Philipp Wolfer (mailto:phw@rubyforge.org)
4
5
  # Copyright:: Copyright (c) 2007, Nigel Graham, Philipp Wolfer
@@ -42,6 +43,7 @@ module MusicBrainz
42
43
 
43
44
  # Includes is a hash with the following fields:
44
45
  # [:aliases] Include aliases (boolean).
46
+ # [:release_groups] Include release groups (boolean).
45
47
  # [:releases] Array of release types that should be included
46
48
  # in the result. All releases of the artist that match
47
49
  # all of those types will be included. Use the constants
@@ -55,7 +57,14 @@ module MusicBrainz
55
57
  # [:track_rels] Include track relationships (boolean).
56
58
  # [:label_rels] Include label relationships (boolean).
57
59
  # [:url_rels] Include url relationships (boolean).
60
+ # [:counts] Includes the track number (boolean).
61
+ # [:release_events] Includes the release events (boolean).
62
+ # [:discs] Include the disc IDs (boolean).
63
+ # [:labels] Include the labels under which the release
58
64
  # [:tags] Include tags (boolean).
65
+ # [:user_tags] Include user tags (boolean).
66
+ # [:ratings] Include ratings (boolean).
67
+ # [:user_ratings] Include user ratings (boolean).
59
68
  #
60
69
  #--
61
70
  # TODO:: Check release types. It's possible that :releases
@@ -63,8 +72,9 @@ module MusicBrainz
63
72
  #++
64
73
  def initialize(includes)
65
74
  Utils.check_options includes,
66
- :aliases, :artist_rels, :release_rels, :track_rels,
67
- :label_rels, :url_rels, :tags, :releases, :va_releases
75
+ :aliases, :artist_rels, :release_rels, :track_rels, :label_rels,
76
+ :url_rels, :tags, :release_groups, :releases, :va_releases, :counts,
77
+ :release_events, :discs, :labels, :user_tags, :ratings, :user_ratings
68
78
  @parameters = Array.new
69
79
  @parameters << 'aliases' if includes[:aliases]
70
80
  @parameters << 'artist-rels' if includes[:artist_rels]
@@ -72,7 +82,15 @@ module MusicBrainz
72
82
  @parameters << 'track-rels' if includes[:track_rels]
73
83
  @parameters << 'label-rels' if includes[:label_rels]
74
84
  @parameters << 'url-rels' if includes[:url_rels]
85
+ @parameters << 'counts' if includes[:counts]
86
+ @parameters << 'release-events' if includes[:release_events]
87
+ @parameters << 'release-groups' if includes[:release_groups]
88
+ @parameters << 'discs' if includes[:discs]
89
+ @parameters << 'labels' if includes[:labels]
75
90
  @parameters << 'tags' if includes[:tags]
91
+ @parameters << 'user_tags' if includes[:user_tags]
92
+ @parameters << 'ratings' if includes[:ratings]
93
+ @parameters << 'user_ratings' if includes[:user_ratings]
76
94
 
77
95
  includes[:releases].each {|release_type|
78
96
  @parameters << 'sa-' + Utils.remove_namespace(release_type.to_s)
@@ -85,17 +103,36 @@ module MusicBrainz
85
103
 
86
104
  end
87
105
 
106
+ # A specification on how much data to return with a release group.
107
+ class ReleaseGroupIncludes < AbstractIncludes
108
+
109
+ # Includes is a hash with the following fields:
110
+ # [:artist] Include track artist (boolean).
111
+ # [:releases] Include releases of the release group (boolean).
112
+ def initialize(includes)
113
+ Utils.check_options includes,
114
+ :artist, :releases
115
+ @parameters = Array.new
116
+ @parameters << 'artist' if includes[:artist]
117
+ @parameters << 'releases' if includes[:releases]
118
+ end
119
+
120
+ end
121
+
88
122
  # A specification on how much data to return with a release.
89
123
  class ReleaseIncludes < AbstractIncludes
90
124
 
91
125
  # Includes is a hash with the following fields:
92
126
  # [:artist] Include track artist (boolean).
93
127
  # [:counts] Includes the track number (boolean).
128
+ # [:release_groups] Includes the release groups (boolean).
94
129
  # [:release_events] Includes the release events (boolean).
95
130
  # [:discs] Include the disc IDs (boolean).
96
131
  # [:tracks] Include the release tracks (boolean).
97
132
  # [:labels] Include the labels under which the release
98
133
  # was published (boolean).
134
+ # [:isrcs] Include the ISRCs of the tracks (boolean).
135
+ # Requires that :tracks is set, too.
99
136
  # [:artist_rels] Include artist relationships (boolean).
100
137
  # [:release_rels] Include release relationships (boolean).
101
138
  # [:track_rels] Include track relationships (boolean).
@@ -104,18 +141,24 @@ module MusicBrainz
104
141
  # [:track_level_rels] Include the relationships for the
105
142
  # single tracks as well (boolean).
106
143
  # [:tags] Include tags (boolean).
144
+ # [:user_tags] Include user tags (boolean).
145
+ # [:ratings] Include ratings (boolean).
146
+ # [:user_ratings] Include user ratings (boolean).
107
147
  def initialize(includes)
108
148
  Utils.check_options includes,
109
- :artist, :counts, :release_events, :discs, :tracks,
110
- :labels, :artist_rels, :release_rels, :track_rels,
111
- :label_rels, :url_rels, :track_level_rels, :tags
149
+ :artist, :counts, :release_groups, :release_events, :discs, :tracks,
150
+ :labels, :isrcs, :artist_rels, :release_rels, :track_rels,
151
+ :label_rels, :url_rels, :track_level_rels, :tags, :user_tags,
152
+ :ratings, :user_ratings
112
153
  @parameters = Array.new
113
154
  @parameters << 'artist' if includes[:artist]
114
155
  @parameters << 'counts' if includes[:counts]
156
+ @parameters << 'release-groups' if includes[:release_groups]
115
157
  @parameters << 'release-events' if includes[:release_events]
116
158
  @parameters << 'discs' if includes[:discs]
117
159
  @parameters << 'tracks' if includes[:tracks]
118
160
  @parameters << 'labels' if includes[:labels]
161
+ @parameters << 'isrcs' if includes[:isrcs]
119
162
  @parameters << 'artist-rels' if includes[:artist_rels]
120
163
  @parameters << 'release-rels' if includes[:release_rels]
121
164
  @parameters << 'track-rels' if includes[:track_rels]
@@ -123,6 +166,9 @@ module MusicBrainz
123
166
  @parameters << 'url-rels' if includes[:url_rels]
124
167
  @parameters << 'track-level-rels' if includes[:track_level_rels]
125
168
  @parameters << 'tags' if includes[:tags]
169
+ @parameters << 'user_tags' if includes[:user_tags]
170
+ @parameters << 'ratings' if includes[:ratings]
171
+ @parameters << 'user_ratings' if includes[:user_ratings]
126
172
  end
127
173
 
128
174
  end
@@ -134,26 +180,35 @@ module MusicBrainz
134
180
  # [:artist] Include track artist (boolean).
135
181
  # [:releases] Includes releases the track appears on (boolean).
136
182
  # [:puids] Include the track's PUIDs (boolean).
183
+ # [:isrcs] Include the track's ISRCs (boolean).
137
184
  # [:artist_rels] Include artist relationships (boolean).
138
185
  # [:release_rels] Include release relationships (boolean).
139
186
  # [:track_rels] Include track relationships (boolean).
140
187
  # [:label_rels] Include label relationships (boolean).
141
188
  # [:url_rels] Include url relationships (boolean).
142
189
  # [:tags] Include tags (boolean).
190
+ # [:user_tags] Include user tags (boolean).
191
+ # [:ratings] Include ratings (boolean).
192
+ # [:user_ratings] Include user ratings (boolean).
143
193
  def initialize(includes)
144
194
  Utils.check_options includes,
145
- :artist, :releases, :puids, :artist_rels, :release_rels,
146
- :track_rels, :label_rels, :url_rels, :tags
195
+ :artist, :releases, :puids, :isrcs, :artist_rels, :release_rels,
196
+ :track_rels, :label_rels, :url_rels, :tags, :user_tags, :ratings,
197
+ :user_ratings
147
198
  @parameters = Array.new
148
199
  @parameters << 'artist' if includes[:artist]
149
200
  @parameters << 'releases' if includes[:releases]
150
201
  @parameters << 'puids' if includes[:puids]
202
+ @parameters << 'isrcs' if includes[:isrcs]
151
203
  @parameters << 'artist-rels' if includes[:artist_rels]
152
204
  @parameters << 'release-rels' if includes[:release_rels]
153
205
  @parameters << 'track-rels' if includes[:track_rels]
154
206
  @parameters << 'label-rels' if includes[:label_rels]
155
207
  @parameters << 'url-rels' if includes[:url_rels]
156
208
  @parameters << 'tags' if includes[:tags]
209
+ @parameters << 'user_tags' if includes[:user_tags]
210
+ @parameters << 'ratings' if includes[:ratings]
211
+ @parameters << 'user_ratings' if includes[:user_ratings]
157
212
  end
158
213
 
159
214
  end
@@ -169,10 +224,13 @@ module MusicBrainz
169
224
  # [:label_rels] Include label relationships (boolean).
170
225
  # [:url_rels] Include url relationships (boolean).
171
226
  # [:tags] Include tags (boolean).
227
+ # [:user_tags] Include user tags (boolean).
228
+ # [:ratings] Include ratings (boolean).
229
+ # [:user_ratings] Include user ratings (boolean).
172
230
  def initialize(includes)
173
231
  Utils.check_options includes,
174
- :aliases, :artist_rels, :release_rels,
175
- :track_rels, :label_rels, :url_rels, :tags
232
+ :aliases, :artist_rels, :release_rels, :track_rels, :label_rels,
233
+ :url_rels, :tags, :user_tags, :ratings, :user_ratings
176
234
  @parameters = Array.new
177
235
  @parameters << 'aliases' if includes[:aliases]
178
236
  @parameters << 'artist-rels' if includes[:artist_rels]
@@ -181,9 +239,12 @@ module MusicBrainz
181
239
  @parameters << 'label-rels' if includes[:label_rels]
182
240
  @parameters << 'url-rels' if includes[:url_rels]
183
241
  @parameters << 'tags' if includes[:tags]
242
+ @parameters << 'user_tags' if includes[:user_tags]
243
+ @parameters << 'ratings' if includes[:ratings]
244
+ @parameters << 'user_ratings' if includes[:user_ratings]
184
245
  end
185
246
 
186
247
  end
187
248
 
188
249
  end
189
- end
250
+ end
@@ -1,4 +1,5 @@
1
- # $Id: mbxml.rb 218 2008-09-02 07:45:33Z phw $
1
+ # -*- coding: utf-8 -*-
2
+ # $Id: mbxml.rb 278 2009-06-07 21:30:51Z phw $
2
3
  #
3
4
  # Author:: Philipp Wolfer (mailto:phw@rubyforge.org)
4
5
  # Copyright:: Copyright (c) 2007, Nigel Graham, Philipp Wolfer
@@ -22,7 +23,7 @@ module MusicBrainz
22
23
  class MBXML
23
24
 
24
25
  # Exception to be raised if a parse error occurs in MBXML.
25
- class ParseError < Exception
26
+ class ParseError < ::Exception
26
27
  end
27
28
 
28
29
  # Create a new MBXML instance to parse a MusicBrainz metadata document.
@@ -47,10 +48,11 @@ module MusicBrainz
47
48
  # Already loaded artists, releases, tracks and labels will get cached
48
49
  # in these variables to link to them if they occure multiple times
49
50
  # inside the same document.
50
- @artists = Hash.new
51
- @releases = Hash.new
52
- @tracks = Hash.new
53
- @labels = Hash.new
51
+ @artists = Hash.new
52
+ @release_groups = Hash.new
53
+ @releases = Hash.new
54
+ @tracks = Hash.new
55
+ @labels = Hash.new
54
56
  end
55
57
 
56
58
  # Read the XML string and create an entity model for the given entity
@@ -61,10 +63,10 @@ module MusicBrainz
61
63
  # Search for the first occuring node of type entity which is a child node
62
64
  # of the metadata element.
63
65
  entity = @document.elements["//[local-name()='metadata' and namespace-uri()='%s']/%s[1]" %
64
- [Model::NS_MMD_1, entity_type]]
66
+ [Model::NS_MMD_1, Utils.entity_type_to_string(entity_type)]]
65
67
 
66
68
  unless entity.nil? or entity.is_a? REXML::Text
67
- create_method = method('create_' + entity.name)
69
+ create_method = method('create_' + entity_type.to_s)
68
70
  create_method.call(entity) if create_method
69
71
  else
70
72
  return nil
@@ -83,7 +85,7 @@ module MusicBrainz
83
85
  # of the metadata element.
84
86
  entity_list = @document.elements[
85
87
  "//[local-name()='metadata' and namespace-uri()='%s']/[local-name()='%s-list' and namespace-uri()='%s'][1]" %
86
- [Model::NS_MMD_1, entity_type, ns]]
88
+ [Model::NS_MMD_1, Utils.entity_type_to_string(entity_type), ns]]
87
89
 
88
90
  unless entity_list.nil? or entity_list.is_a? REXML::Text
89
91
  collection = Model::ScoredCollection.new(entity_list.attributes['count'],
@@ -121,7 +123,10 @@ module MusicBrainz
121
123
  end
122
124
 
123
125
  # Read all defined data fields
124
- artist.id = node.attributes['id']
126
+ read_mbid(node, artist)
127
+ read_relationships(node, artist)
128
+ read_ratings(node, artist)
129
+ read_tag_list(node.elements['tag-list'], artist.tags)
125
130
  if node.attributes['type']
126
131
  artist.type = Utils.add_namespace(node.attributes['type'])
127
132
  end
@@ -142,20 +147,46 @@ module MusicBrainz
142
147
  read_release_list(node.elements['release-list'], artist.releases) {|release|
143
148
  release.artist = artist unless release.artist
144
149
  }
145
-
146
- # Read the relation list
147
- if node.elements['relation-list']
148
- node.elements.each('relation-list') {|relation_node|
149
- read_relation_list(relation_node) {|relation|
150
- artist.add_relation relation
151
- }
152
- }
150
+
151
+ # Read the release group list
152
+ read_release_group_list(node.elements['release-group-list'], artist.release_groups) {|release_group|
153
+ release_group.artist = artist unless release_group.artist
154
+ }
155
+
156
+ return artist
157
+ end
158
+
159
+ # Iterate over a list of release groups and add them to the target collection.
160
+ #
161
+ # The node must be of the type <em>release-group-list</em>.
162
+ def read_release_group_list(list_node, target_collection, read_scores=false)
163
+ read_list(list_node, target_collection, 'release-group', read_scores) do |a|
164
+ yield a if block_given?
165
+ end
166
+ end
167
+
168
+ # Create a +ReleaseGroup+ object from the given release-group node.
169
+ def create_release_group(node)
170
+ if node.attributes['id'] and @release_groups[node.attributes['id']]
171
+ release_group = @release_groups[node.attributes['id']]
172
+ else
173
+ release_group = @factory.new_release_group
174
+ @release_groups[node.attributes['id']] = release_group
153
175
  end
154
176
 
155
- # Read the tag list
156
- read_tag_list(node.elements['tag-list'], artist.tags)
177
+ # Read all defined data fields
178
+ read_mbid(node, release_group)
179
+ release_group.title = node.elements['title'].text if node.elements['title']
180
+ release_group.artist = create_artist(node.elements['artist']) if node.elements['artist']
157
181
 
158
- return artist
182
+ read_types(node, release_group.types)
183
+
184
+ # Read the release list
185
+ read_release_list(node.elements['release-list'], release_group.releases) {|release|
186
+ release.artist = release_group.artist unless release.artist
187
+ }
188
+
189
+ return release_group
159
190
  end
160
191
 
161
192
  # Iterate over a list of releases and add them to the target collection.
@@ -179,15 +210,16 @@ module MusicBrainz
179
210
  end
180
211
 
181
212
  # Read all defined data fields
182
- release.id = node.attributes['id']
213
+ read_mbid(node, release)
214
+ read_relationships(node, release)
215
+ read_ratings(node, release)
216
+ read_tag_list(node.elements['tag-list'], release.tags)
183
217
  release.title = node.elements['title'].text if node.elements['title']
184
218
  release.asin = node.elements['asin'].text if node.elements['asin']
185
219
  release.artist = create_artist(node.elements['artist']) if node.elements['artist']
220
+ release.release_group = create_release_group(node.elements['release-group']) if node.elements['release-group']
186
221
 
187
- # Read the types
188
- node.attributes['type'].split(' ').each {|type|
189
- release.types << Utils.add_namespace(type)
190
- } if node.attributes['type']
222
+ read_types(node, release.types)
191
223
 
192
224
  # Read the text representation information.
193
225
  if text_representation = node.elements['text-representation']
@@ -207,18 +239,6 @@ module MusicBrainz
207
239
  # Read the disc list
208
240
  read_disc_list(node.elements['disc-list'], release.discs)
209
241
 
210
- # Read the relation list
211
- if node.elements['relation-list']
212
- node.elements.each('relation-list') {|relation_node|
213
- read_relation_list(relation_node) {|relation|
214
- release.add_relation relation
215
- }
216
- }
217
- end
218
-
219
- # Read the tag list
220
- read_tag_list(node.elements['tag-list'], release.tags)
221
-
222
242
  return release
223
243
  end
224
244
 
@@ -241,7 +261,10 @@ module MusicBrainz
241
261
  end
242
262
 
243
263
  # Read all defined data fields
244
- track.id = node.attributes['id']
264
+ read_mbid(node, track)
265
+ read_relationships(node, track)
266
+ read_ratings(node, track)
267
+ read_tag_list(node.elements['tag-list'], track.tags)
245
268
  track.title = node.elements['title'].text if node.elements['title']
246
269
  track.duration = node.elements['duration'].text.to_i if node.elements['duration']
247
270
  track.artist = create_artist(node.elements['artist']) if node.elements['artist']
@@ -251,20 +274,9 @@ module MusicBrainz
251
274
  release.tracks << track
252
275
  }
253
276
 
254
- # Read the PUID list
277
+ # Read the PUID and ISRC lists
255
278
  read_puid_list(node.elements['puid-list'], track.puids)
256
-
257
- # Read the relation list
258
- if node.elements['relation-list']
259
- node.elements.each('relation-list') {|relation_node|
260
- read_relation_list(relation_node) {|relation|
261
- track.add_relation relation
262
- }
263
- }
264
- end
265
-
266
- # Read the tag list
267
- read_tag_list(node.elements['tag-list'], track.tags)
279
+ read_isrc_list(node.elements['isrc-list'], track.isrcs)
268
280
 
269
281
  return track
270
282
  end
@@ -288,7 +300,10 @@ module MusicBrainz
288
300
  end
289
301
 
290
302
  # Read all defined data fields
291
- label.id = node.attributes['id']
303
+ read_mbid(node, label)
304
+ read_relationships(node, label)
305
+ read_ratings(node, label)
306
+ read_tag_list(node.elements['tag-list'], label.tags)
292
307
  if node.attributes['type']
293
308
  label.type = Utils.add_namespace(node.attributes['type'])
294
309
  end
@@ -310,18 +325,6 @@ module MusicBrainz
310
325
  # Read the release list
311
326
  read_release_list(node.elements['release-list'], label.releases)
312
327
 
313
- # Read the relation list
314
- if node.elements['relation-list']
315
- node.elements.each('relation-list') {|relation_node|
316
- read_relation_list(relation_node) {|relation|
317
- label.add_relation relation
318
- }
319
- }
320
- end
321
-
322
- # Read the tag list
323
- read_tag_list(node.elements['tag-list'], label.tags)
324
-
325
328
  return label
326
329
  end
327
330
 
@@ -400,6 +403,20 @@ module MusicBrainz
400
403
  return node.attributes['id']
401
404
  end
402
405
 
406
+ # Iterate over a list of ISRCs and add them to the target collection.
407
+ #
408
+ # The node must be of the type <em>isrc-list</em>.
409
+ def read_isrc_list(list_node, target_collection)
410
+ read_list(list_node, target_collection, 'isrc') do |a|
411
+ yield a if block_given?
412
+ end
413
+ end
414
+
415
+ # Create an ISRC
416
+ def create_isrc(node)
417
+ return Model::ISRC.parse(node.attributes['id'])
418
+ end
419
+
403
420
  # Iterate over a list of discs and add them to the target collection.
404
421
  #
405
422
  # The node must be of the type <em>disc-list</em>.
@@ -510,6 +527,51 @@ module MusicBrainz
510
527
  return user_model
511
528
  end
512
529
 
530
+ # Read attributes common to all entities
531
+ def read_mbid(node, entity)
532
+ entity.id = node.attributes['id']
533
+ end
534
+
535
+ # Read the relation list
536
+ def read_relationships(node, entity)
537
+ if node.elements['relation-list']
538
+ node.elements.each('relation-list') {|relation_node|
539
+ read_relation_list(relation_node) {|relation|
540
+ entity.add_relation relation
541
+ }
542
+ }
543
+ end
544
+ end
545
+
546
+ # Read the type attribute
547
+ def read_types(node, target_collection)
548
+ node.attributes['type'].split(' ').each {|type|
549
+ target_collection << Utils.add_namespace(type)
550
+ } if node.attributes['type']
551
+ end
552
+
553
+ # Read the ratings
554
+ def read_ratings(node, entity)
555
+ if node.elements['rating']
556
+ entity.rating = create_rating(node.elements['rating'])
557
+ end
558
+
559
+ if node.elements['user-rating']
560
+ entity.user_rating = create_user_rating(node.elements['user-rating'])
561
+ end
562
+ end
563
+
564
+ # Create a +Rating+ object from the given rating or user-rating node.
565
+ def create_rating(node)
566
+ rating = @factory.new_rating
567
+ rating.value = node.text.to_f
568
+ if node.attributes['votes-count']
569
+ rating.count = node.attributes['votes-count'].to_i
570
+ end
571
+ return rating
572
+ end
573
+ alias :create_user_rating create_rating
574
+
513
575
  # Helper method that reads a list of a special node type.
514
576
  # There must be a method create_{child_name} which returns an
515
577
  # instance of the corresponding model.
@@ -518,7 +580,7 @@ module MusicBrainz
518
580
  target_collection.offset = list_node.attributes['offset'].to_i
519
581
  target_collection.count = list_node.attributes['count'].to_i
520
582
  MBXML.each_element(list_node, child_name, ns) do |child|
521
- model = method('create_' + child_name).call(child)
583
+ model = method('create_' + child_name.sub('-', '_')).call(child)
522
584
  if read_scores
523
585
  score = child.attributes['ext:score'].to_i
524
586
  entry = Model::ScoredCollection::Entry.new(model, score)
@@ -554,4 +616,4 @@ module MusicBrainz
554
616
  end
555
617
 
556
618
  end
557
- end
619
+ end