Skip to content

Commit

Permalink
Implement the Nfl.schedule class method
Browse files Browse the repository at this point in the history
  • Loading branch information
RLovelett committed Nov 4, 2012
1 parent 1e6db52 commit a5d3573
Show file tree
Hide file tree
Showing 4 changed files with 179 additions and 1 deletion.
90 changes: 90 additions & 0 deletions lib/nfl.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
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, :away, :status

def initialize(xml)
if xml.is_a? Nokogiri::XML::Element
@id = xml["id"]
@scheduled = Time.parse xml["scheduled"]
@home = xml["home"]
@away = xml["away"]
@status = xml["status"]
end
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(error_json, { 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
14 changes: 13 additions & 1 deletion lib/sports_data_api.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
require "sports_data_api/version"
require "nokogiri"
require "rest_client"

module SportsDataApi
# Your code goes here...
def self.key
"garbage"
end

def self.access_level
"t"
end

autoload :Nfl, File.join(File.dirname(__FILE__), 'nfl')

class Exception < ::Exception; end
end
67 changes: 67 additions & 0 deletions spec/lib/nfl_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
require 'spec_helper'

describe SportsDataApi::Nfl do
let(:key) { "1234567890abcdef" }
describe ".schedule" do
it "creates a valid Sports Data LLC url" do
SportsDataApi.stub(:key).and_return(key)
RestClient.stub(:get).with("http://api.sportsdatallc.org/nfl-t1/2012/REG/schedule.xml", params: { api_key: key }).and_return(schedule_xml)
subject.schedule(2012, :REG)
end
it "creates a SportsDataApi::Exception when there is no response from the api" do
error = RestClient::ResourceNotFound.new
error.stub_chain(:response, :headers).and_return(Hash.new)
SportsDataApi.stub(:key).and_return(key)
RestClient.stub(:get).and_raise(error)
expect { subject.schedule(2999, :REG) }.to raise_error(SportsDataApi::Exception)
end

describe "returned data structures" do
before(:each) { RestClient.stub(:get).and_return(schedule_xml) }
let(:season) { SportsDataApi::Nfl.schedule(2012, :REG) }
describe "SportsDataApi::Nfl::Season" do
subject { season }
it { should be_an_instance_of(SportsDataApi::Nfl::Season) }
its(:year) { should eq 2012 }
its(:type) { should eq :REG }
its(:weeks) { should have(17).weeks }
end
describe "SportsDataApi::Nfl::Week" do
subject { season.weeks.first }
it { should be_an_instance_of(SportsDataApi::Nfl::Week) }
its(:number) { should eq 1 }
its(:games) { should have(16).games }
end
describe "SportsDataApi::Nfl::Game" do
subject { season.weeks.first.games.first }
it { should be_an_instance_of(SportsDataApi::Nfl::Game) }
its(:id) { should eq "8c0bce5a-7ca2-41e5-9838-d1b8c356ddc3" }
its(:scheduled) { should eq Time.new(2012, 9, 5, 19, 30, 00, "-05:00") }
its(:home) { should eq "NYG" }
its(:away) { should eq "DAL" }
its(:status) { should eq "closed" }
end
end
end

describe ".season?" do
context :PRE do
it { subject.season?(:PRE).should be_true }
end
context :REG do
it { subject.season?(:REG).should be_true }
end
context :PST do
it { subject.season?(:PST).should be_true }
end
context :pre do
it { subject.season?(:pre).should be_false }
end
context :reg do
it { subject.season?(:reg).should be_false }
end
context :pst do
it { subject.season?(:pst).should be_false }
end
end
end
9 changes: 9 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@
# loaded once.
#
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration

def load_xml(filename)
File.read("#{File.dirname(__FILE__)}/xml/#{filename}.xml")
end

def schedule_xml
load_xml("schedule")
end

RSpec.configure do |config|
config.treat_symbols_as_metadata_keys_with_true_values = true
config.run_all_when_everything_filtered = true
Expand Down

0 comments on commit a5d3573

Please sign in to comment.