bassnode-discogs 0.3.2

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 (59) hide show
  1. data/.gitignore +5 -0
  2. data/COPYING +619 -0
  3. data/LICENSE +5 -0
  4. data/README.markdown +75 -0
  5. data/Rakefile +27 -0
  6. data/bassnode-discogs.gemspec +18 -0
  7. data/lib/discogs.rb +21 -0
  8. data/lib/wrapper/resource.rb +79 -0
  9. data/lib/wrapper/resource_mappings.rb +84 -0
  10. data/lib/wrapper/resources/artist.rb +37 -0
  11. data/lib/wrapper/resources/artist_release.rb +17 -0
  12. data/lib/wrapper/resources/format.rb +11 -0
  13. data/lib/wrapper/resources/generic_list.rb +29 -0
  14. data/lib/wrapper/resources/image.rb +11 -0
  15. data/lib/wrapper/resources/label.rb +16 -0
  16. data/lib/wrapper/resources/label_release.rb +17 -0
  17. data/lib/wrapper/resources/release.rb +22 -0
  18. data/lib/wrapper/resources/release_artist.rb +18 -0
  19. data/lib/wrapper/resources/release_label.rb +10 -0
  20. data/lib/wrapper/resources/search.rb +61 -0
  21. data/lib/wrapper/resources/search_result.rb +16 -0
  22. data/lib/wrapper/resources/track.rb +15 -0
  23. data/lib/wrapper/wrapper.rb +109 -0
  24. data/spec/resource_spec.rb +27 -0
  25. data/spec/resources/artist_release_spec.rb +59 -0
  26. data/spec/resources/artist_spec.rb +15 -0
  27. data/spec/resources/format_spec.rb +41 -0
  28. data/spec/resources/generic_list_spec.rb +66 -0
  29. data/spec/resources/image_spec.rb +43 -0
  30. data/spec/resources/label_release_spec.rb +55 -0
  31. data/spec/resources/label_spec.rb +15 -0
  32. data/spec/resources/release_artist_spec.rb +43 -0
  33. data/spec/resources/release_label_spec.rb +31 -0
  34. data/spec/resources/release_spec.rb +15 -0
  35. data/spec/resources/search_result_spec.rb +47 -0
  36. data/spec/resources/search_spec.rb +15 -0
  37. data/spec/resources/track_spec.rb +56 -0
  38. data/spec/samples/valid_artist.xml +76 -0
  39. data/spec/samples/valid_artist_release.xml +8 -0
  40. data/spec/samples/valid_description_list.xml +5 -0
  41. data/spec/samples/valid_format.xml +7 -0
  42. data/spec/samples/valid_genre_list.xml +5 -0
  43. data/spec/samples/valid_image.xml +1 -0
  44. data/spec/samples/valid_label.xml +34 -0
  45. data/spec/samples/valid_label_release.xml +8 -0
  46. data/spec/samples/valid_release.xml +99 -0
  47. data/spec/samples/valid_release_artist.xml +8 -0
  48. data/spec/samples/valid_release_label.xml +1 -0
  49. data/spec/samples/valid_search_result.xml +6 -0
  50. data/spec/samples/valid_search_results_1.xml +142 -0
  51. data/spec/samples/valid_search_results_2.xml +206 -0
  52. data/spec/samples/valid_track.xml +16 -0
  53. data/spec/spec_helper.rb +36 -0
  54. data/spec/wrapper_methods/get_artist_spec.rb +109 -0
  55. data/spec/wrapper_methods/get_label_spec.rb +89 -0
  56. data/spec/wrapper_methods/get_release_spec.rb +123 -0
  57. data/spec/wrapper_methods/search_spec.rb +330 -0
  58. data/spec/wrapper_spec.rb +180 -0
  59. metadata +125 -0
data/README.markdown ADDED
@@ -0,0 +1,75 @@
1
+ Discogs::Wrapper
2
+ ================
3
+
4
+ ABOUT
5
+ -----
6
+ A 100% Ruby wrapper of the Discogs.com API. No dependencies, no extra gems. :)
7
+
8
+ Discogs::Wrapper abstracts all the nasty boilerplate code needed to interact with the Discogs API. It gives you direct access to the information you need.
9
+
10
+ Full support for everything in version 1.0 of the API:
11
+
12
+ * Artists
13
+ * Releases
14
+ * Labels
15
+ * Searching (all of the above)
16
+
17
+ Please, [see the Wiki](http://github.com/buntine/discogs/wiki) for helpful documentation.
18
+
19
+ The API is [documented here](http://www.discogs.com/help/api).
20
+
21
+ INSTALLATION
22
+ ------------
23
+ You can install the library via Rubygems:
24
+ $ gem sources -a http://gems.github.com
25
+ $ sudo gem install buntine-discogs
26
+
27
+ USAGE
28
+ -----
29
+ To use this library, you must supply a valid Discogs API key.
30
+ require 'discogs'
31
+
32
+ wrapper = Discogs::Wrapper.new("my_api_key")
33
+
34
+ Accessing information is easy:
35
+ artist = wrapper.get_artist("Master's Hammer")
36
+ release = wrapper.get_release("611973") # Supply an ID.
37
+ label = wrapper.get_label("Monitor Records")
38
+ search_results = wrapper.search("Necrovore")
39
+
40
+ artist.name # => "Master's Hammer"
41
+ artist.releases[0].title # => "Finished"
42
+ artist.releases[1].year # => "1989"
43
+ artist.releases[4].extraartists # => [ "Arakain", "Debustrol" ]
44
+
45
+ release.title # => "Ritual"
46
+ release.labels[0].name # => "Osmose Productions"
47
+ release.formats[0].descriptions[0] # => "LP"
48
+ release.styles # => [ "Black Metal", "Death Metal" ]
49
+ release.tracklist[1].title # => "Pad modly"
50
+
51
+ label.images[0].width # => "220"
52
+ label.releases.length # => 22
53
+ label.releases[3].artist # => "Root"
54
+ label.releases[7].catno # => "MON007"
55
+
56
+ search.total_results # => 124
57
+ search.total_pages # => 7
58
+ search.current_page # => 1
59
+
60
+ # Exact results
61
+ search.exact[0].type # => "artist"
62
+ search.exact[0].title # => "Necrovore"
63
+ search.exact(:label)[0].title # => "Necrovores Records"
64
+ search.closest(:artist) # => <Discogs::Search::Result:0x324ad3e2>
65
+
66
+ # All results
67
+ search.results[3].title # => "Necrovore - Demo '87"
68
+ search.results[3].summary # => "First and only demo tape"
69
+ search.results(:release)[0] # => <Discogs::Search::Result:0x343de34a>
70
+
71
+
72
+ LICENSE
73
+ -------
74
+
75
+ <a rel="license" href="http://creativecommons.org/licenses/by/3.0/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by/3.0/80x15.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">Discogs::Wrapper</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/buntine/discogs" property="cc:attributionName" rel="cc:attributionURL">Andrew Buntine</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0 Unported License</a>.<br />Based on a work at <a xmlns:dct="http://purl.org/dc/terms/" href="http://www.discogs.com/help/api" rel="dct:source">www.discogs.com</a>.
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ require 'rake'
2
+ require 'spec'
3
+ require 'spec/rake/spectask'
4
+ require 'rake/gempackagetask'
5
+
6
+ task :default => :spec
7
+
8
+ desc "Run all specs in spec directory"
9
+ Spec::Rake::SpecTask.new(:spec) do |t|
10
+ t.spec_opts = ["--colour", "--format progress", "--loadby mtime", "--reverse"]
11
+ t.spec_files = FileList[ 'spec/**/*_spec.rb' ]
12
+ end
13
+
14
+ desc "Run all specs and generate RCov report"
15
+ Spec::Rake::SpecTask.new('cov') do |t|
16
+ t.spec_files = FileList['spec/**/*.rb']
17
+ t.spec_opts = ["--colour"]
18
+ t.rcov = true
19
+ t.rcov_opts = ['-T --no-html --exclude', 'spec\/,gems\/']
20
+ end
21
+
22
+ spec = eval(File.read("bassnode-discogs.gemspec"))
23
+
24
+ Rake::GemPackageTask.new(spec) do |pkg|
25
+ # pkg.need_zip = true
26
+ # pkg.need_tar = true
27
+ end
@@ -0,0 +1,18 @@
1
+ Gem::Specification.new do |s|
2
+
3
+ s.name = "bassnode-discogs"
4
+ s.version = "0.3.2"
5
+ s.date = "2011-04-12"
6
+ s.summary = "Discogs::Wrapper is a full wrapper for the http://www.discogs.com API"
7
+ s.homepage = "http://www.github.com/bassnode/discogs"
8
+ s.email = "info@andrewbuntine.com"
9
+ s.authors = ["Andrew Buntine", "Ed Hickey"]
10
+ s.rubyforge_project = 'bassnode-discogs'
11
+ s.description = "Discogs::Wrapper is a full wrapper for the http://www.discogs.com API"
12
+
13
+ s.files = `git ls-files`.split("\n")
14
+ s.test_files = `git ls-files -- {spec}/*`.split("\n")
15
+
16
+ s.platform = Gem::Platform::RUBY
17
+
18
+ end
data/lib/discogs.rb ADDED
@@ -0,0 +1,21 @@
1
+
2
+ ## Discogs::Wrapper
3
+ ## by Andrew Buntine, 2009
4
+ ##
5
+ ## This library provides full access to the Discogs.com API v1.0
6
+ ##
7
+ ## Please file all bug reports at http://www.github.com/buntine/discogs, or
8
+ ## email me at info@andrewbuntine.com.
9
+ ##
10
+ ## Enjoy!
11
+
12
+ # Application namespace.
13
+ module Discogs; end
14
+
15
+ # Custom exceptions.
16
+ class Discogs::InvalidAPIKey < Exception; end
17
+ class Discogs::UnknownResource < Exception; end
18
+ class Discogs::InternalServerError < Exception; end
19
+
20
+ # Loading sequence.
21
+ require File.dirname(__FILE__) + "/wrapper/wrapper"
@@ -0,0 +1,79 @@
1
+ # Represents a generic resource in the Discogs API.
2
+
3
+ require File.dirname(__FILE__) + "/resource_mappings"
4
+
5
+ class Discogs::Resource
6
+
7
+ include Discogs::ResourceMappings
8
+
9
+ def initialize(content)
10
+ @content = content
11
+ end
12
+
13
+ def original_content
14
+ @content
15
+ end
16
+
17
+ # Builds the resource with it's content.
18
+ def build!(remove_resp=true)
19
+ document = REXML::Document.new(@content, :ignore_whitespace_nodes => :all)
20
+ root_node = document.root
21
+
22
+ # Ignore the <resp> element if necessary.
23
+ if remove_resp and document.root.expanded_name == "resp"
24
+ root_node = root_node[0]
25
+ end
26
+
27
+ set_accessors_from_attributes(root_node)
28
+
29
+ # Traverse node children.
30
+ root_node.each_element do |element|
31
+ name = element.expanded_name.to_sym
32
+ setter = (name.to_s + "=").to_sym
33
+
34
+ singular = find_resource_for_name(name, :singular)
35
+ plural = singular ? nil : find_resource_for_name(name, :plural)
36
+
37
+ # Create an instance of the named resource and build it.
38
+ if !singular.nil?
39
+ nested_object = singular.send(:new, element.to_s)
40
+ self.send(setter, nested_object.build!)
41
+
42
+ # Setup an array and build each child.
43
+ elsif !plural.nil?
44
+ set_accessors_from_attributes(element)
45
+
46
+ self.send(setter, [])
47
+ element.each_element do |sub_element|
48
+ nested_object = plural.send(:new, sub_element.to_s)
49
+ self.send(name) << nested_object.build!
50
+ end
51
+
52
+ elsif self.respond_to? setter
53
+ self.send(setter, element.text)
54
+ end
55
+ end
56
+
57
+ self
58
+ end
59
+
60
+ def build_with_resp!
61
+ build!(false)
62
+ end
63
+
64
+ private
65
+
66
+ # Sets accessors on _self_ from the attributes of the given element.
67
+ def set_accessors_from_attributes(element)
68
+ element.attributes.each_attribute do |attribute|
69
+ setter = (attribute.expanded_name + "=").to_sym
70
+
71
+ if self.respond_to? setter
72
+ self.send(setter, attribute.value)
73
+ end
74
+ end
75
+ end
76
+
77
+ end
78
+
79
+ Dir[File.join(File.dirname(__FILE__), "resources", "*.rb")].each { |file| require file }
@@ -0,0 +1,84 @@
1
+ # Abstracts the resource-mapping class methods.
2
+ #
3
+ # Each "resource" in the wrapper maps to one or more elements
4
+ # in the API response. This way they can be recursively built
5
+ # without having to manually specify it in each class.
6
+
7
+ module Discogs::ResourceMappings
8
+
9
+ def self.included(base)
10
+ base.extend ClassMethods
11
+ end
12
+
13
+ module ClassMethods
14
+
15
+ # Helper method to map resource to element in API response.
16
+ def map_to(*elements)
17
+ self.class_eval <<-EOF
18
+ def self.element_names
19
+ #{elements.inspect}
20
+ end
21
+ EOF
22
+ end
23
+
24
+ # Helper method to map pluralised resource to element in API response.
25
+ def map_to_plural(*elements)
26
+ self.class_eval <<-EOF
27
+ def self.plural_element_names
28
+ #{elements.inspect}
29
+ end
30
+ EOF
31
+ end
32
+
33
+ # Used by root classes (Discogs::Artist, etc) that should be built internally.
34
+ def no_mapping
35
+ self.class_eval <<-EOF
36
+ def self.element_names; []; end
37
+ def self.plural_element_names; []; end
38
+ EOF
39
+ end
40
+
41
+ # Element defaults to prevent excess boilerplate code.
42
+ def element_names
43
+ [ self.to_s.split("::")[-1].downcase.to_sym ]
44
+ end
45
+ def plural_element_names
46
+ [ (self.element_names[0].to_s + "s").to_sym ]
47
+ end
48
+
49
+ end
50
+
51
+ private
52
+
53
+ def find_resource_for_name(name, type=:singular)
54
+ method = if type == :singular
55
+ :element_names
56
+ else
57
+ :plural_element_names
58
+ end
59
+
60
+ find_resource do |klass|
61
+ klass.constants.find do |const|
62
+ if klass.const_get(const).respond_to? method
63
+ klass.const_get(const).send(method).any? { |element| element.eql?(name) }
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ # Look in _namespace_ for a matching resource class.
70
+ # First looks in the children of _self_ namespace, and then looks more
71
+ # generally. Returns nil if nothing is found.
72
+ def find_resource(namespace=self.class, &matcher)
73
+ match = matcher.call(namespace)
74
+
75
+ if match
76
+ match = namespace.const_get(match)
77
+ elsif namespace == self.class
78
+ match = find_resource(Discogs, &matcher)
79
+ end
80
+
81
+ return match
82
+ end
83
+
84
+ end
@@ -0,0 +1,37 @@
1
+ # Represents an artist in the Discogs API.
2
+
3
+ class Discogs::Artist < Discogs::Resource
4
+
5
+ no_mapping
6
+
7
+ attr_accessor :name,
8
+ :realname,
9
+ :images,
10
+ :urls,
11
+ :namevariations,
12
+ :aliases,
13
+ :members,
14
+ :releases
15
+
16
+ def main_releases
17
+ filter_releases("Main")
18
+ end
19
+
20
+ def bootlegs
21
+ filter_releases("UnofficialRelease")
22
+ end
23
+
24
+ def appearances
25
+ filter_releases("Appearance")
26
+ end
27
+
28
+ private
29
+
30
+ # Simple helper for filtering a particular type of release.
31
+ def filter_releases(type)
32
+ self.releases.find_all do |release|
33
+ release.type == type
34
+ end
35
+ end
36
+
37
+ end
@@ -0,0 +1,17 @@
1
+ # Represents an artist's release in the Discogs API.
2
+
3
+ require File.dirname(__FILE__) + "/artist"
4
+
5
+ class Discogs::Artist::Release < Discogs::Resource
6
+
7
+ attr_accessor :id,
8
+ :status,
9
+ :type,
10
+ :title,
11
+ :artist,
12
+ :format,
13
+ :year,
14
+ :label,
15
+ :trackinfo
16
+
17
+ end
@@ -0,0 +1,11 @@
1
+ # Represents a release format in the Discogs API.
2
+
3
+ require File.dirname(__FILE__) + "/release"
4
+
5
+ class Discogs::Release::Format < Discogs::Resource
6
+
7
+ attr_accessor :name,
8
+ :qty,
9
+ :descriptions
10
+
11
+ end
@@ -0,0 +1,29 @@
1
+ # Represents a generic list of items in the Discogs API.
2
+
3
+ class Discogs::GenericList < Discogs::Resource
4
+
5
+ map_to :descriptions, :genres, :aliases, :namevariations, :styles, :urls, :members, :sublabels
6
+
7
+ map_to_plural :lists
8
+
9
+ # Overload build method to provide custom process for
10
+ # converting contents into something useful.
11
+ def build!
12
+ @items = []
13
+ document = REXML::Document.new(@content)
14
+
15
+ document.root.each_element do |element|
16
+ @items << element.text
17
+ end
18
+
19
+ @items
20
+ end
21
+
22
+ # Provides post-build access to the list.
23
+ def [](index)
24
+ if @items.is_a?(Array)
25
+ @items[index]
26
+ end
27
+ end
28
+
29
+ end
@@ -0,0 +1,11 @@
1
+ # Represents an image in the Discogs API.
2
+
3
+ class Discogs::Image < Discogs::Resource
4
+
5
+ attr_accessor :uri,
6
+ :uri150,
7
+ :width,
8
+ :height,
9
+ :type
10
+
11
+ end
@@ -0,0 +1,16 @@
1
+ # Represents a label in the Discogs API.
2
+
3
+ class Discogs::Label < Discogs::Resource
4
+
5
+ no_mapping
6
+
7
+ attr_accessor :name,
8
+ :contactinfo,
9
+ :profile,
10
+ :parentlabel,
11
+ :images,
12
+ :urls,
13
+ :sublabels,
14
+ :releases
15
+
16
+ end
@@ -0,0 +1,17 @@
1
+ # Represents a labels release in the Discogs API.
2
+
3
+ require File.dirname(__FILE__) + "/label"
4
+
5
+ class Discogs::Label::Release < Discogs::Resource
6
+
7
+ attr_accessor :id,
8
+ :status,
9
+ :type,
10
+ :catno,
11
+ :artist,
12
+ :title,
13
+ :format,
14
+ :year,
15
+ :trackinfo
16
+
17
+ end
@@ -0,0 +1,22 @@
1
+ # Represents a release in the Discogs API.
2
+
3
+ class Discogs::Release < Discogs::Resource
4
+
5
+ no_mapping
6
+
7
+ attr_accessor :id,
8
+ :status,
9
+ :title,
10
+ :country,
11
+ :released,
12
+ :notes,
13
+ :images,
14
+ :artists,
15
+ :extraartists,
16
+ :labels,
17
+ :formats,
18
+ :styles,
19
+ :genres,
20
+ :tracklist
21
+
22
+ end
@@ -0,0 +1,18 @@
1
+ # Represents an release's artist in the Discogs API.
2
+
3
+ require File.dirname(__FILE__) + "/track"
4
+
5
+ class Discogs::Release::Artist < Discogs::Resource
6
+
7
+ map_to_plural :artists, :extraartists
8
+
9
+ attr_accessor :name,
10
+ :role,
11
+ :join,
12
+ :anv,
13
+ :tracks
14
+
15
+ end
16
+
17
+ # Define other classes that also replicate this structure.
18
+ class Discogs::Release::Track::Artist < Discogs::Release::Artist; end
@@ -0,0 +1,10 @@
1
+ # Represents a Releases Label in the Discogs API.
2
+
3
+ require File.dirname(__FILE__) + "/release"
4
+
5
+ class Discogs::Release::Label < Discogs::Resource
6
+
7
+ attr_accessor :catno,
8
+ :name
9
+
10
+ end
@@ -0,0 +1,61 @@
1
+ # Represents a search resultset in the Discogs API.
2
+
3
+ class Discogs::Search < Discogs::Resource
4
+
5
+ no_mapping
6
+
7
+ attr_accessor :exactresults,
8
+ :searchresults,
9
+ :start,
10
+ :end,
11
+ :numResults
12
+
13
+ def total_results
14
+ self.numResults.to_i
15
+ end
16
+
17
+ def current_page
18
+ (start.to_i / page_size) + 1
19
+ end
20
+
21
+ def total_pages
22
+ (total_results.to_f / page_size).ceil
23
+ end
24
+
25
+ def last_page?
26
+ current_page == total_pages
27
+ end
28
+
29
+ def exact(filter=nil)
30
+ filter_results(filter, self.exactresults)
31
+ end
32
+
33
+ def results(filter=nil)
34
+ filter_results(filter, self.searchresults)
35
+ end
36
+
37
+ # Returns the closest exact result for _filter_, or nil.
38
+ def closest(filter)
39
+ exact(filter)[0] rescue nil
40
+ end
41
+
42
+ private
43
+
44
+ # An easy way for filtering a particular "type" of result (Artist, Release, etc)
45
+ def filter_results(filter, results)
46
+ results ||= []
47
+
48
+ if filter.nil?
49
+ results
50
+ else
51
+ results.find_all do |result|
52
+ result.type == filter.to_s
53
+ end
54
+ end
55
+ end
56
+
57
+ def page_size
58
+ self.end.to_i - (self.start.to_i - 1)
59
+ end
60
+
61
+ end
@@ -0,0 +1,16 @@
1
+ # Represents a single search result in the Discogs API.
2
+
3
+ require File.dirname(__FILE__) + "/search"
4
+
5
+ class Discogs::Search::Result < Discogs::Resource
6
+
7
+ map_to_plural :exactresults, :searchresults
8
+
9
+ attr_accessor :num,
10
+ :type,
11
+ :title,
12
+ :uri,
13
+ :anv,
14
+ :summary
15
+
16
+ end
@@ -0,0 +1,15 @@
1
+ # Represents a track in the Discogs API.
2
+
3
+ require File.dirname(__FILE__) + "/release"
4
+
5
+ class Discogs::Release::Track < Discogs::Resource
6
+
7
+ map_to_plural :tracklist
8
+
9
+ attr_accessor :position,
10
+ :title,
11
+ :duration,
12
+ :artists,
13
+ :extraartists
14
+
15
+ end