rbrainz 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. data/LICENSE +25 -0
  2. data/README +11 -0
  3. data/Rakefile +110 -0
  4. data/TODO +24 -0
  5. data/doc/README.rdoc +68 -0
  6. data/examples/getartist.rb +54 -0
  7. data/lib/rbrainz.rb +11 -0
  8. data/lib/rbrainz/data/countrynames.rb +259 -0
  9. data/lib/rbrainz/data/languagenames.rb +404 -0
  10. data/lib/rbrainz/data/scriptnames.rb +64 -0
  11. data/lib/rbrainz/model.rb +48 -0
  12. data/lib/rbrainz/model/alias.rb +23 -0
  13. data/lib/rbrainz/model/artist.rb +54 -0
  14. data/lib/rbrainz/model/disc.rb +30 -0
  15. data/lib/rbrainz/model/entity.rb +72 -0
  16. data/lib/rbrainz/model/incomplete_date.rb +76 -0
  17. data/lib/rbrainz/model/label.rb +55 -0
  18. data/lib/rbrainz/model/mbid.rb +82 -0
  19. data/lib/rbrainz/model/release.rb +50 -0
  20. data/lib/rbrainz/model/release_event.rb +34 -0
  21. data/lib/rbrainz/model/track.rb +27 -0
  22. data/lib/rbrainz/webservice.rb +6 -0
  23. data/lib/rbrainz/webservice/filter.rb +132 -0
  24. data/lib/rbrainz/webservice/includes.rb +150 -0
  25. data/lib/rbrainz/webservice/mbxml.rb +404 -0
  26. data/lib/rbrainz/webservice/query.rb +61 -0
  27. data/lib/rbrainz/webservice/webservice.rb +69 -0
  28. data/test/lib/test_entity.rb +58 -0
  29. data/test/lib/testing_helper.rb +13 -0
  30. data/test/test-data/README +13 -0
  31. data/test/test-data/invalid/artist/basic_1.xml +12 -0
  32. data/test/test-data/invalid/artist/basic_2.xml +12 -0
  33. data/test/test-data/invalid/artist/empty_1.xml +0 -0
  34. data/test/test-data/invalid/artist/empty_2.xml +3 -0
  35. data/test/test-data/invalid/artist/empty_3.xml +7 -0
  36. data/test/test-data/invalid/artist/search_result_1.xml +11 -0
  37. data/test/test-data/valid/artist/Tchaikovsky-1.xml +90 -0
  38. data/test/test-data/valid/artist/Tori_Amos_1.xml +8 -0
  39. data/test/test-data/valid/artist/Tori_Amos_2.xml +53 -0
  40. data/test/test-data/valid/artist/Tori_Amos_3.xml +25 -0
  41. data/test/test-data/valid/artist/Tori_Amos_4.xml +14 -0
  42. data/test/test-data/valid/artist/Tori_Amos_5.xml +13 -0
  43. data/test/test-data/valid/artist/empty_1.xml +7 -0
  44. data/test/test-data/valid/artist/empty_2.xml +11 -0
  45. data/test/test-data/valid/artist/search_result_1.xml +19 -0
  46. data/test/test-data/valid/label/Atlantic_Records_1.xml +9 -0
  47. data/test/test-data/valid/label/Atlantic_Records_2.xml +11 -0
  48. data/test/test-data/valid/label/search_result_1.xml +14 -0
  49. data/test/test-data/valid/release/Highway_61_Revisited_1.xml +68 -0
  50. data/test/test-data/valid/release/Little_Earthquakes_1.xml +24 -0
  51. data/test/test-data/valid/release/Little_Earthquakes_2.xml +73 -0
  52. data/test/test-data/valid/release/Mission_Impossible_2.xml +155 -0
  53. data/test/test-data/valid/release/Under_the_Pink_1.xml +16 -0
  54. data/test/test-data/valid/release/Under_the_Pink_2.xml +14 -0
  55. data/test/test-data/valid/release/Under_the_Pink_3.xml +16 -0
  56. data/test/test-data/valid/release/search_result_1.xml +29 -0
  57. data/test/test-data/valid/track/Silent_All_These_Years_1.xml +7 -0
  58. data/test/test-data/valid/track/Silent_All_These_Years_2.xml +21 -0
  59. data/test/test-data/valid/track/Silent_All_These_Years_3.xml +16 -0
  60. data/test/test-data/valid/track/Silent_All_These_Years_4.xml +30 -0
  61. data/test/test-data/valid/track/Silent_All_These_Years_5.xml +20 -0
  62. data/test/test-data/valid/track/search_result_1.xml +45 -0
  63. data/test/test-data/valid/user/User_1.xml +15 -0
  64. data/test/test_alias.rb +50 -0
  65. data/test/test_artist.rb +132 -0
  66. data/test/test_artist_filter.rb +36 -0
  67. data/test/test_artist_includes.rb +63 -0
  68. data/test/test_disc.rb +38 -0
  69. data/test/test_incomplete_date.rb +60 -0
  70. data/test/test_label.rb +129 -0
  71. data/test/test_label_filter.rb +36 -0
  72. data/test/test_label_includes.rb +55 -0
  73. data/test/test_mbid.rb +99 -0
  74. data/test/test_mbxml.rb +368 -0
  75. data/test/test_query.rb +24 -0
  76. data/test/test_release.rb +161 -0
  77. data/test/test_release_event.rb +67 -0
  78. data/test/test_release_filter.rb +57 -0
  79. data/test/test_release_includes.rb +73 -0
  80. data/test/test_track.rb +102 -0
  81. data/test/test_track_filter.rb +57 -0
  82. data/test/test_track_includes.rb +61 -0
  83. data/test/test_webservice.rb +23 -0
  84. metadata +138 -0
@@ -0,0 +1,48 @@
1
+ # $Id: model.rb 13 2007-05-22 22:59:57Z phw $
2
+ # Copyright (c) 2007, Philipp Wolfer
3
+ # All rights reserved.
4
+ # See LICENSE for permissions.
5
+
6
+ module MusicBrainz
7
+ module Model
8
+
9
+ # Namespace for all MusicBrainz metadata.
10
+ NS_MMD_1 = 'http://musicbrainz.org/ns/mmd-1.0#'
11
+
12
+ # Namespace for MusicBrainz relations.
13
+ NS_REL_1 = 'http://musicbrainz.org/ns/rel-1.0#'
14
+
15
+ # Namespace for MusicBrainz extensions.
16
+ NS_EXT_1 = 'http://musicbrainz.org/ns/ext-1.0#'
17
+
18
+ # Defines the format of an UUID (Universally Unique Identifier)
19
+ UUID_REGEXP = /^[a-f0-9]{8}(-[a-f0-9]{4}){3}-[a-f0-9]{12}$/
20
+
21
+ # The format of a MusicBrainz identifier was wrong.
22
+ class InvalidMBIDError < Exception
23
+ end
24
+
25
+ # The format of a MusicBrainz UUID was wrong.
26
+ class InvalidUUIDError < Exception
27
+ end
28
+
29
+ # An unknown entity was encountered.
30
+ # Valid entities are only :artist, :release, :track and :label.
31
+ class UnknownEntityError < Exception
32
+ end
33
+
34
+ # The entity type of a MBID didn't match the type of the entity.
35
+ class EntityTypeNotMatchingError < Exception
36
+ end
37
+
38
+ end
39
+ end
40
+
41
+ require 'rbrainz/data/countrynames'
42
+ require 'rbrainz/data/languagenames'
43
+ require 'rbrainz/data/scriptnames'
44
+
45
+ require 'rbrainz/model/artist'
46
+ require 'rbrainz/model/label'
47
+ require 'rbrainz/model/release'
48
+ require 'rbrainz/model/track'
@@ -0,0 +1,23 @@
1
+ # $Id: alias.rb 4 2007-05-21 02:04:26Z phw $
2
+ # Copyright (c) 2007, Philipp Wolfer
3
+ # All rights reserved.
4
+ # See LICENSE for permissions.
5
+
6
+ module MusicBrainz
7
+ module Model
8
+
9
+ # An artist alias.
10
+ #
11
+ # See http://musicbrainz.org/doc/ArtistAlias.
12
+ class Alias
13
+
14
+ attr_accessor :name, :type, :script
15
+
16
+ def to_s
17
+ return name.to_s
18
+ end
19
+
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,54 @@
1
+ # $Id: artist.rb 13 2007-05-22 22:59:57Z phw $
2
+ # Copyright (c) 2007, Philipp Wolfer
3
+ # All rights reserved.
4
+ # See LICENSE for permissions.
5
+
6
+ require 'rbrainz/model/entity'
7
+ require 'rbrainz/model/alias'
8
+ require 'rbrainz/model/incomplete_date'
9
+
10
+ module MusicBrainz
11
+ module Model
12
+
13
+ # An artist in the MusicBrainz DB.
14
+ #
15
+ # See http://musicbrainz.org/doc/Artist.
16
+ class Artist < Entity
17
+
18
+ TYPE_PERSON = NS_MMD_1 + 'Person'
19
+ TYPE_GROUP = NS_MMD_1 + 'Group'
20
+
21
+ attr_accessor :name, :sort_name, :disambiguation,
22
+ :type, :aliases, :releases
23
+
24
+ attr_reader :begin_date, :end_date
25
+
26
+ def initialize
27
+ @aliases = Array.new
28
+ @releases = Array.new
29
+ end
30
+
31
+ # Set the begin date of this artist.
32
+ #
33
+ # Should be an IncompleteDate object or
34
+ # a date string, which will get converted
35
+ # into an IncompleteDate.
36
+ def begin_date=(date)
37
+ date = IncompleteDate.new date unless date.is_a? IncompleteDate
38
+ @begin_date = date
39
+ end
40
+
41
+ # Set the end date of this artist.
42
+ #
43
+ # Should be an IncompleteDate object or
44
+ # a date string, which will get converted
45
+ # into an IncompleteDate.
46
+ def end_date=(date)
47
+ date = IncompleteDate.new date unless date.is_a? IncompleteDate
48
+ @end_date = date
49
+ end
50
+
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,30 @@
1
+ # $Id: disc.rb 15 2007-05-23 14:31:36Z phw $
2
+ # Copyright (c) 2007, Philipp Wolfer
3
+ # All rights reserved.
4
+ # See LICENSE for permissions.
5
+
6
+ module MusicBrainz
7
+ module Model
8
+
9
+ # Represents an audio CD.
10
+ #
11
+ # A disc has a disc id, which is calculated from the
12
+ # CD's table of contents (TOC). It also can include
13
+ # the numbers of sectors on the CD.
14
+ #
15
+ # The disc id is mainly used to lookup a release in
16
+ # the MusicBrainz database the matches a given disc
17
+ # id. See Webservice::ReleaseFilter for details on
18
+ # this.
19
+ #
20
+ # See http://wiki.musicbrainz.org/DiscID.
21
+ #
22
+ # TODO: Currently the calculation of a disc ID is not supported.
23
+ class Disc
24
+
25
+ attr_accessor :id, :sectors
26
+
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,72 @@
1
+ # $Id: entity.rb 15 2007-05-23 14:31:36Z phw $
2
+ # Copyright (c) 2007, Philipp Wolfer
3
+ # All rights reserved.
4
+ # See LICENSE for permissions.
5
+
6
+ require 'rbrainz/model/mbid'
7
+
8
+ module MusicBrainz
9
+ module Model
10
+
11
+ # Superclass for all entities.
12
+ #
13
+ # TODO: implement relations.
14
+ class Entity
15
+
16
+ attr_reader :id
17
+
18
+ # Set the MBID.
19
+ #
20
+ # +mbid+ should be an instance of +MBID+ or a string
21
+ # representing either a complete MBID URI or just the
22
+ # UUID part of it. If it is a complete URI the entity
23
+ # part of the URI must match the entity type returned
24
+ # by +entity_type+ or an +EntityTypeNotMatchingError+
25
+ # will be raised.
26
+ #
27
+ # Raises: +UnknownEntityError+, +InvalidUUIDError+,
28
+ # +EntityTypeNotMatchingError+
29
+ def id=(mbid)
30
+ # If this already is an instance of MBID store it directly.
31
+ if mbid.is_a? MBID
32
+ @id = mbid
33
+ elsif mbid.nil?
34
+ @id = nil
35
+ else
36
+ # Try to create an MBID from URI
37
+ begin
38
+ @id = MBID.from_uri(mbid)
39
+ rescue InvalidMBIDError => e
40
+ # Try it again and use mbid as the UUID
41
+ @id = MBID.from_uuid(self.entity_type, mbid)
42
+ end
43
+ end
44
+
45
+ # Check if the entity type of @id matches that of the current object.
46
+ unless @id.nil? or @id.entity == self.entity_type
47
+ exception = EntityTypeNotMatchingError.new(@id.entity.to_s)
48
+ @id = nil
49
+ raise exception
50
+ end
51
+ end
52
+
53
+ # Returns the entity type of the entity class.
54
+ #
55
+ # Depending on the class this is <tt>:artist</tt>, <tt>:release</tt>,
56
+ # <tt>:track</tt> or <tt>:label</tt>.
57
+ def self.entity_type
58
+ self.name.sub('MusicBrainz::Model::', '').downcase.to_sym
59
+ end
60
+
61
+ # Returns the entity type of the instance.
62
+ #
63
+ # Depending on the class this is <tt>:artist</tt>, <tt>:release</tt>,
64
+ # <tt>:track</tt> or <tt>:label</tt>.
65
+ def entity_type
66
+ self.class.entity_type
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,76 @@
1
+ # $Id: incomplete_date.rb 17 2007-05-23 16:51:11Z phw $
2
+ # Copyright (c) 2007, Philipp Wolfer
3
+ # All rights reserved.
4
+ # See LICENSE for permissions.
5
+
6
+ require 'date'
7
+
8
+ module MusicBrainz
9
+ module Model
10
+
11
+ # Represents an incomplete date. An incomplete date is
12
+ # a date which can be defined without day or without
13
+ # month and day. It can be written as <em>YYYY</em>,
14
+ # <em>YYYY-MM</em> or <em>YYYY-MM-DD</em>.
15
+ class IncompleteDate
16
+
17
+ attr_reader :year, :month, :day
18
+
19
+ # Include the Comparable module to make incomplete dates
20
+ # comparable and sortable.
21
+ include Comparable
22
+
23
+ # TODO: Validation of the date
24
+ def initialize(date)
25
+ @year = nil
26
+ @month = nil
27
+ @day = nil
28
+ if date = date.to_s and date =~ /^\d{4}(-\d{2}){0,2}$/
29
+ @year = date[0..3].to_i if date.size >= 4
30
+ @month = date[5..6].to_i if date.size >= 7
31
+ @day = date[8..9].to_i if date.size == 10
32
+ elsif not date.empty?
33
+ raise ArgumentError
34
+ end
35
+ end
36
+
37
+ # Returns the incomplete date in its textual form
38
+ # <em>YYYY</em>, <em>YYYY-MM</em> or <em>YYYY-MM-DD</em>.
39
+ #
40
+ # TODO: Allow formatting options similiar to Date.to_s
41
+ def to_s
42
+ date = @year.to_s
43
+ [@month, @day].each {|value|
44
+ date += '-%02d' % value if value
45
+ }
46
+ return date
47
+ end
48
+
49
+ # Compare this incomplete date with another incomplete date.
50
+ # If two incomplete dates are compared of which one date has
51
+ # less information than the other only the information
52
+ # present in both incomplete dates is used for comparison.
53
+ # That means that the dates 1980-08-22, 1980-08 and 1980 are
54
+ # all considered equal if compared to one another since it
55
+ # can't be decided if e.g. the date 1980-08 is earlier or later
56
+ # than 1980-08-22.
57
+ #
58
+ # As a consequence of this a list of +IncompleteDate+ objects
59
+ # won't get sorted in the lexical order of their string
60
+ # representations. If you need a lexical order you must convert
61
+ # these objects to strings before ordering them.
62
+ def <=>(other)
63
+ result = self.year <=> other.year
64
+ if result == 0 and self.month and other.month
65
+ result = self.month <=> other.month
66
+ if result == 0 and self.day and other.day
67
+ result = self.day <=> other.day
68
+ end
69
+ end
70
+ return result
71
+ end
72
+
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,55 @@
1
+ # $Id: label.rb 13 2007-05-22 22:59:57Z phw $
2
+ # Copyright (c) 2007, Philipp Wolfer
3
+ # All rights reserved.
4
+ # See LICENSE for permissions.
5
+
6
+ require 'rbrainz/model/entity'
7
+ require 'rbrainz/model/incomplete_date'
8
+
9
+ module MusicBrainz
10
+ module Model
11
+
12
+ # A label in the MusicBrainz DB.
13
+ #
14
+ # See http://musicbrainz.org/doc/Label.
15
+ class Label < Entity
16
+
17
+ TYPE_DISTRIBUTOR = NS_MMD_1 + 'Distributor'
18
+ TYPE_HOLDING = NS_MMD_1 + 'Holding'
19
+ TYPE_ORIGINAL_PRODUCTION = NS_MMD_1 + 'OriginalProduction'
20
+ TYPE_BOOTLEG_PRODUCTION = NS_MMD_1 + 'BootlegProduction'
21
+ TYPE_REISSUE_PRODUCTION = NS_MMD_1 + 'ReissueProduction'
22
+
23
+ attr_accessor :name, :sort_name, :disambiguation,
24
+ :code, :country, :type, :releases
25
+
26
+ attr_reader :founding_date, :dissolving_date
27
+
28
+ def initialize
29
+ @releases = Array.new
30
+ end
31
+
32
+ # Set the founding date of the label.
33
+ #
34
+ # Should be an IncompleteDate object or
35
+ # a date string, which will get converted
36
+ # into an IncompleteDate.
37
+ def founding_date=(date)
38
+ date = IncompleteDate.new date unless date.is_a? IncompleteDate
39
+ @founding_date = date
40
+ end
41
+
42
+ # Set the dissolving date of the label.
43
+ #
44
+ # Should be an IncompleteDate object or
45
+ # a date string, which will get converted
46
+ # into an IncompleteDate.
47
+ def dissolving_date=(date)
48
+ date = IncompleteDate.new date unless date.is_a? IncompleteDate
49
+ @dissolving_date = date
50
+ end
51
+
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,82 @@
1
+ # $Id: mbid.rb 17 2007-05-23 16:51:11Z phw $
2
+ # Copyright (c) 2007, Philipp Wolfer
3
+ # All rights reserved.
4
+ # See LICENSE for permissions.
5
+
6
+ require 'rbrainz/model'
7
+
8
+ module MusicBrainz
9
+ module Model
10
+
11
+ # Represents a MusicBrainz identifier.
12
+ #
13
+ # A MusicBrainz identifier is an URI identifying a resource like an artist or a track.
14
+ # It consists of an URI prefix, the entity type it refers to and an UUID that
15
+ # identifies the referenced entity.
16
+ #
17
+ # See http://musicbrainz.org/doc/MusicBrainzIdentifier.
18
+ #
19
+ # Example: http://musicbrainz.org/artist/6a2ca1ac-408d-49b0-a7f6-cd608f2f684f.
20
+ class MBID
21
+
22
+ attr_reader :entity, :uuid
23
+
24
+ ENTITY_URI = 'http://musicbrainz.org/%s/%s'
25
+ ENTITY_URI_REGEXP = /^http:\/\/musicbrainz.org\/(artist|release|track|label)\/([a-f0-9]{8}(-[a-f0-9]{4}){3}-[a-f0-9]{12})\/?$/
26
+
27
+ # We make new private. Use from_uri or from_uuid instead.
28
+ private_class_method :new
29
+
30
+ # Creates a new MBID from a MBID URI, e.g.
31
+ # http://musicbrainz.org/artist/6a2ca1ac-408d-49b0-a7f6-cd608f2f684f
32
+ def self.from_uri(uri)
33
+ if match = ENTITY_URI_REGEXP.match(uri)
34
+ entity = match[1]
35
+ uuid = match[2]
36
+ else
37
+ raise InvalidMBIDError.new(uri.inspect)
38
+ end
39
+ from_uuid(entity, uuid)
40
+ end
41
+
42
+ # Create a new MBID from the entity type and the UUID.
43
+ #
44
+ # The entity type must be <tt>:artist</tt>, <tt>:release</tt>,
45
+ # <tt>:track</tt> or <tt>:label</tt>. The UUID is the last
46
+ # part of the URI, e.g. <tt>6a2ca1ac-408d-49b0-a7f6-cd608f2f684f</tt>.
47
+ #
48
+ # Raises: +UnknownEntityError+, +InvalidUUIDError+
49
+ def self.from_uuid(entity, uuid)
50
+ if entity.nil? or entity == '' or
51
+ not [:artist, :release, :track, :label].include? entity.to_sym
52
+ raise UnknownEntityError.new(entity.to_s)
53
+ end
54
+ unless uuid.is_a? String and uuid =~ UUID_REGEXP
55
+ raise InvalidUUIDError.new(uuid.inspect)
56
+ end
57
+ new(entity.to_sym, uuid)
58
+ end
59
+
60
+ # Initialize the UUID given the entity type and an UUID.
61
+ def initialize(entity, uuid) # :notnew:
62
+ @entity = entity
63
+ @uuid = uuid
64
+ end
65
+
66
+ # Returns the string representation of the MBID (that is the complete URI).
67
+ def to_s
68
+ ENTITY_URI % [entity.to_s, uuid]
69
+ end
70
+
71
+ # Compares this MBID with another one.
72
+ #
73
+ # Two MBIDs are considered equal if both their entity
74
+ # type and their UUID are equal.
75
+ def ==(other)
76
+ self.entity == other.entity and self.uuid == other.uuid
77
+ end
78
+
79
+ end
80
+
81
+ end
82
+ end