require 'rexml/document' require 'rexml_extensions' require 'net/http' require 'rubygems' require 'active_support' module Lastfm module Cache class Basic < Hash attr_reader :created_on def initialize(*args) @created_on = Time.now end def cache(uri, data) self[uri] = data end def expire(pattern) each { |uri, val| delete uri if uri =~ pattern } end end end class LastfmError < StandardError; end class Chart < Array CHART_TYPES = %w{recenttracks weeklyartistchart weeklytrackchart topartists toptracks topalbums weeklyalbumchart} @@host = 'ws.audioscrobbler.com' @@port = 80 @@base_url = '/1.0/user' @@cache_class = Cache::Basic @@cache = @@cache_class.new @@expire_cache_every = 1.days @@auto_expire_cache = true cattr_accessor :host, :port, :base_url, :cache, :cache_class, :expire_cache_every, :auto_expire_cache def initialize(user, type) @user, @type = user, type raise LastfmError, "Chart type #{type} is not valid." unless CHART_TYPES.include? type parse(request) end protected def uri "#{base_url}/#{@user}/#{@type.to_s}.xml" end def request check_cache if auto_expire_cache return cache[uri] if cache.has_key? uri Net::HTTP.start(host, port) do |http| cache.cache uri, http.get(uri).body end rescue raise LastfmError, "Connection to last.fm failed with error: #{$!}" end def parse(response) doc = REXML::Document.new response doc.root.elements.each do |element| push element.to_hash(HashWithIndifferentAccess.new) end rescue LastfmError, 'Invalid response. Cannot be parsed.' end def check_cache self.cache = cache_class.new if Time.now > (cache.created_on + expire_cache_every) end end end