module SportsDataApi module Nfl class Exception < ::Exception end class Season attr_reader :year, :type, :weeks def initialize(xml) @weeks = [] if xml.is_a? Nokogiri::XML::NodeSet @year = xml.first["season"].to_i @type = xml.first["type"].to_sym @weeks = xml.first.xpath("week").map do |week_xml| Week.new(week_xml) end end end end class Week attr_reader :number, :games def initialize(xml) @games = [] if xml.is_a? Nokogiri::XML::Element @number = xml["week"].to_i @games = xml.xpath("game").map do |game_xml| Game.new(game_xml) end end end end class Game attr_reader :id, :scheduled, :home, :home_team, :away, :away_team, :status, :quarter, :clock def initialize(xml) xml = xml.first if xml.is_a? Nokogiri::XML::NodeSet if xml.is_a? Nokogiri::XML::Element @id = xml["id"] @scheduled = Time.parse xml["scheduled"] @home = xml["home"] @away = xml["away"] @status = xml["status"] @quarter = xml["quarter"].to_i @clock = xml["clock"] team_xml = xml.xpath("team") @home_team = Team.new(team_xml.first) @away_team = Team.new(team_xml.last) end end end class Team attr_reader :id, :name, :market, :remaining_challenges, :remaining_timeouts, :score, :quarters def initialize(xml) if xml.is_a? Nokogiri::XML::Element @id = xml["id"] @name = xml["name"] @market = xml["market"] @remaining_challenges = xml["remaining_challenges"].to_i @remaining_timeouts = xml["remaining_timeouts"].to_i @quarters = xml.xpath("scoring/quarter").map do |quarter| quarter["points"].to_i end @quarters = @quarters.fill(0, @quarters.size, 4 - @quarters.size) end end # Sum the score of each quarter def score @quarters.inject(:+) end end BASE_URL = "http://api.sportsdatallc.org/nfl-%{access_level}%{version}" SEASONS = [:PRE, :REG, :PST] def self.schedule(year, season, version = 1) base_url = BASE_URL % { access_level: SportsDataApi.access_level, version: version } season = season.to_s.upcase.to_sym raise SportsDataApi::Nfl::Exception.new("#{season} is not a valid season") unless season?(season) url = "#{base_url}/#{year}/#{season}/schedule.xml" begin # Perform the request response = RestClient.get(url, params: { api_key: SportsDataApi.key }) # Load the XML and ignore namespaces in Nokogiri schedule = Nokogiri::XML(response.to_s) schedule.remove_namespaces! return Season.new(schedule.xpath("/season")) rescue RestClient::Exception => e message = if e.response.headers.key? :x_server_error JSON.parse(e.response.headers[:x_server_error], { symbolize_names: true })[:message] elsif e.response.headers.key? :x_mashery_error_code e.response.headers[:x_mashery_error_code] else "The server did not specify a message" end raise SportsDataApi::Exception, message end end ## # def self.boxscore(year, season, week, home, away, version = 1) base_url = BASE_URL % { access_level: SportsDataApi.access_level, version: version } season = season.to_s.upcase.to_sym raise SportsDataApi::Nfl::Exception.new("#{season} is not a valid season") unless season?(season) url = "#{base_url}/#{year}/#{season}/#{week}/#{away}/#{home}/boxscore.xml" begin # Perform the request response = RestClient.get(url, params: { api_key: SportsDataApi.key }) # Load the XML and ignore namespaces in Nokogiri boxscore = Nokogiri::XML(response.to_s) boxscore.remove_namespaces! return Game.new(boxscore.xpath("/game")) rescue RestClient::Exception => e message = if e.response.headers.key? :x_server_error JSON.parse(e.response.headers[:x_server_error], { symbolize_names: true })[:message] elsif e.response.headers.key? :x_mashery_error_code e.response.headers[:x_mashery_error_code] else "The server did not specify a message" end raise SportsDataApi::Exception, message end end ## # Check if the requested season is a valid # NFL season type. # # The only valid types are: :PRE, :REG, :PST def self.season?(season) SEASONS.include?(season) end end end