sports_data_api 0.0.1 → 0.0.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.
data/lib/nfl.rb CHANGED
@@ -34,17 +34,47 @@ module SportsDataApi
34
34
  end
35
35
 
36
36
  class Game
37
- attr_reader :id, :scheduled, :home, :away, :status
37
+ attr_reader :id, :scheduled, :home, :home_team, :away, :away_team, :status, :quarter, :clock
38
38
 
39
39
  def initialize(xml)
40
+ xml = xml.first if xml.is_a? Nokogiri::XML::NodeSet
40
41
  if xml.is_a? Nokogiri::XML::Element
41
42
  @id = xml["id"]
42
43
  @scheduled = Time.parse xml["scheduled"]
43
44
  @home = xml["home"]
44
45
  @away = xml["away"]
45
46
  @status = xml["status"]
47
+ @quarter = xml["quarter"].to_i
48
+ @clock = xml["clock"]
49
+
50
+ team_xml = xml.xpath("team")
51
+ @home_team = Team.new(team_xml.first)
52
+ @away_team = Team.new(team_xml.last)
53
+ end
54
+ end
55
+ end
56
+
57
+ class Team
58
+ attr_reader :id, :name, :market, :remaining_challenges, :remaining_timeouts, :score, :quarters
59
+
60
+ def initialize(xml)
61
+ if xml.is_a? Nokogiri::XML::Element
62
+ @id = xml["id"]
63
+ @name = xml["name"]
64
+ @market = xml["market"]
65
+ @remaining_challenges = xml["remaining_challenges"].to_i
66
+ @remaining_timeouts = xml["remaining_timeouts"].to_i
67
+ @quarters = xml.xpath("scoring/quarter").map do |quarter|
68
+ quarter["points"].to_i
69
+ end
70
+ @quarters = @quarters.fill(0, @quarters.size, 4 - @quarters.size)
46
71
  end
47
72
  end
73
+
74
+ # Sum the score of each quarter
75
+ def score
76
+ @quarters.inject(:+)
77
+ end
48
78
  end
49
79
 
50
80
  BASE_URL = "http://api.sportsdatallc.org/nfl-%{access_level}%{version}"
@@ -77,6 +107,35 @@ module SportsDataApi
77
107
  end
78
108
  end
79
109
 
110
+ ##
111
+ #
112
+ def self.boxscore(year, season, week, home, away, version = 1)
113
+ base_url = BASE_URL % { access_level: SportsDataApi.access_level, version: version }
114
+ season = season.to_s.upcase.to_sym
115
+ raise SportsDataApi::Nfl::Exception.new("#{season} is not a valid season") unless season?(season)
116
+ url = "#{base_url}/#{year}/#{season}/#{week}/#{home}/#{away}/boxscore.xml"
117
+
118
+ begin
119
+ # Perform the request
120
+ response = RestClient.get(url, params: { api_key: SportsDataApi.key })
121
+
122
+ # Load the XML and ignore namespaces in Nokogiri
123
+ boxscore = Nokogiri::XML(response.to_s)
124
+ boxscore.remove_namespaces!
125
+
126
+ return Game.new(boxscore.xpath("/game"))
127
+ rescue RestClient::Exception => e
128
+ message = if e.response.headers.key? :x_server_error
129
+ JSON.parse(error_json, { symbolize_names: true })[:message]
130
+ elsif e.response.headers.key? :x_mashery_error_code
131
+ e.response.headers[:x_mashery_error_code]
132
+ else
133
+ "The server did not specify a message"
134
+ end
135
+ raise SportsDataApi::Exception, message
136
+ end
137
+ end
138
+
80
139
  ##
81
140
  # Check if the requested season is a valid
82
141
  # NFL season type.
@@ -1,3 +1,3 @@
1
1
  module SportsDataApi
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -5,11 +5,19 @@ require "time"
5
5
 
6
6
  module SportsDataApi
7
7
  def self.key
8
- "garbage"
8
+ @key ||= "garbage"
9
+ end
10
+
11
+ def self.key=(new_key)
12
+ @key = new_key
9
13
  end
10
14
 
11
15
  def self.access_level
12
- "t"
16
+ @access_level ||= "t"
17
+ end
18
+
19
+ def self.access_level=(new_level)
20
+ @access_level = new_level
13
21
  end
14
22
 
15
23
  autoload :Nfl, File.join(File.dirname(__FILE__), 'nfl')
data/spec/lib/nfl_spec.rb CHANGED
@@ -44,6 +44,64 @@ describe SportsDataApi::Nfl do
44
44
  end
45
45
  end
46
46
 
47
+ describe ".boxscore" do
48
+ it "creates a valid SportsData LLC url" do
49
+ SportsDataApi.stub(:key).and_return(key)
50
+ RestClient.stub(:get).with("http://api.sportsdatallc.org/nfl-t1/2012/REG/9/MIA/IND/boxscore.xml", params: { api_key: key }).and_return(boxscore_xml)
51
+ subject.boxscore(2012, :REG, 9, "MIA", "IND")
52
+ end
53
+ it "creates a SportsDataApi::Exception when there is no response from the api" do
54
+ error = RestClient::ResourceNotFound.new
55
+ error.stub_chain(:response, :headers).and_return(Hash.new)
56
+ SportsDataApi.stub(:key).and_return(key)
57
+ RestClient.stub(:get).and_raise(error)
58
+ expect { subject.boxscore(2999, :REG, 9, "MIA", "IND") }.to raise_error(SportsDataApi::Exception)
59
+ end
60
+ describe "returned data structures" do
61
+ let(:boxscore) { SportsDataApi::Nfl.boxscore(2012, :REG, 9, "IND", "MIA") }
62
+ before(:each) { RestClient.stub(:get).and_return(boxscore_xml) }
63
+ describe "SportsDataApi::Nfl::Game" do
64
+ subject { boxscore }
65
+ it { should be_an_instance_of(SportsDataApi::Nfl::Game) }
66
+ its(:id) { should eq "55d0b262-98ff-49fa-95c8-5ab8ec8cbd34" }
67
+ its(:scheduled) { should eq Time.new(2012, 11, 4, 18, 00, 00, "+00:00") }
68
+ its(:home) { should eq "IND" }
69
+ its(:away) { should eq "MIA" }
70
+ its(:status) { should eq "inprogress" }
71
+ its(:quarter) { should eq 2 }
72
+ its(:clock) { should eq "02:29" }
73
+ its(:home_team) { should be_an_instance_of(SportsDataApi::Nfl::Team) }
74
+ its(:away_team) { should be_an_instance_of(SportsDataApi::Nfl::Team) }
75
+ end
76
+ describe "SportsDataApi::Nfl::Team" do
77
+ describe "home team" do
78
+ subject { boxscore.home_team }
79
+ it { should be_an_instance_of(SportsDataApi::Nfl::Team) }
80
+ its(:id) { should eq "IND" }
81
+ its(:name) { should eq "Colts" }
82
+ its(:market) { should eq "Indianapolis" }
83
+ its(:remaining_challenges) { should eq 1 }
84
+ its(:remaining_timeouts) { should eq 2 }
85
+ its(:score) { should eq 10 }
86
+ its(:quarters) { should have(4).scores }
87
+ its(:quarters) { should include(7, 3, 0, 0) }
88
+ end
89
+ describe "away team" do
90
+ subject { boxscore.away_team }
91
+ it { should be_an_instance_of(SportsDataApi::Nfl::Team) }
92
+ its(:id) { should eq "MIA" }
93
+ its(:name) { should eq "Dolphins" }
94
+ its(:market) { should eq "Miami" }
95
+ its(:remaining_challenges) { should eq 2 }
96
+ its(:remaining_timeouts) { should eq 2 }
97
+ its(:score) { should eq 17 }
98
+ its(:quarters) { should have(4).scores }
99
+ its(:quarters) { should include(3, 14, 0, 0) }
100
+ end
101
+ end
102
+ end
103
+ end
104
+
47
105
  describe ".season?" do
48
106
  context :PRE do
49
107
  it { subject.season?(:PRE).should be_true }
@@ -0,0 +1,18 @@
1
+ require "spec_helper"
2
+
3
+ describe SportsDataApi do
4
+ context "default values" do
5
+ its(:key) { should eq "garbage" }
6
+ its(:access_level) { should eq "t" }
7
+ end
8
+ context "user supplied values" do
9
+ let(:key) { "testing_key123" }
10
+ let(:level) { "b" }
11
+ before(:each) do
12
+ SportsDataApi.key = key
13
+ SportsDataApi.access_level = level
14
+ end
15
+ its(:key) { should eq key }
16
+ its(:access_level) { should eq level }
17
+ end
18
+ end
data/spec/spec_helper.rb CHANGED
@@ -15,6 +15,10 @@ def schedule_xml
15
15
  load_xml("schedule")
16
16
  end
17
17
 
18
+ def boxscore_xml
19
+ load_xml("boxscore")
20
+ end
21
+
18
22
  RSpec.configure do |config|
19
23
  config.treat_symbols_as_metadata_keys_with_true_values = true
20
24
  config.run_all_when_everything_filtered = true
@@ -0,0 +1,93 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!-- Generation started at Sun Nov 04 19:18:23 +0000 2012 -->
3
+ <game xmlns="http://feed.elasticstats.com/schema/nfl/boxscore-v1.0.xsd" id="55d0b262-98ff-49fa-95c8-5ab8ec8cbd34" scheduled="2012-11-04T18:00:00+00:00" home="IND" away="MIA" status="inprogress" quarter="2" clock="02:29">
4
+ <team id="IND" name="Colts" market="Indianapolis" remaining_challenges="1" remaining_timeouts="2">
5
+ <scoring points="10">
6
+ <quarter number="1" points="7"/>
7
+ <quarter number="2" points="3"/>
8
+ </scoring>
9
+ </team>
10
+ <team id="MIA" name="Dolphins" market="Miami" remaining_challenges="2" remaining_timeouts="2">
11
+ <scoring points="17">
12
+ <quarter number="1" points="3"/>
13
+ <quarter number="2" points="14"/>
14
+ </scoring>
15
+ </team>
16
+ <scoring_drives>
17
+ <drive sequence="1" clock="09:34" quarter="1" team="MIA">
18
+ <score type="fieldgoal" clock="04:21" quarter="1" points="3">
19
+ <summary>
20
+ <![CDATA[5-D.Carpenter 37 yards Field Goal is Good.]]>
21
+ </summary>
22
+ <links>
23
+ <link rel="summary" href="/2012/REG/9/MIA/IND/plays/f98b06d5-cfa1-475f-9d4b-b794599501d7.xml" type="application/xml"/>
24
+ </links>
25
+ </score>
26
+ </drive>
27
+ <drive sequence="2" clock="04:15" quarter="1" team="IND">
28
+ <score type="touchdown" clock=":53" quarter="1" points="6">
29
+ <summary>
30
+ <![CDATA[12-A.Luck complete to 87-R.Wayne. 87-R.Wayne runs 9 yards for a touchdown.]]>
31
+ </summary>
32
+ <links>
33
+ <link rel="summary" href="/2012/REG/9/MIA/IND/plays/000eabfe-4b36-40d7-ad4b-6f137ff9e615.xml" type="application/xml"/>
34
+ </links>
35
+ </score>
36
+ <score type="extrapoint" clock=":53" quarter="1" points="1">
37
+ <summary>
38
+ <![CDATA[4-A.Vinatieri extra point is good.]]>
39
+ </summary>
40
+ <links>
41
+ <link rel="summary" href="/2012/REG/9/MIA/IND/plays/429691e9-d940-4647-9e6e-99ebbe6e11e8.xml" type="application/xml"/>
42
+ </links>
43
+ </score>
44
+ </drive>
45
+ <drive sequence="3" clock=":47" quarter="1" team="MIA">
46
+ <score type="touchdown" clock="13:32" quarter="2" points="6">
47
+ <summary>
48
+ <![CDATA[17-R.Tannehill complete to 42-C.Clay. 42-C.Clay runs 31 yards for a touchdown.]]>
49
+ </summary>
50
+ <links>
51
+ <link rel="summary" href="/2012/REG/9/MIA/IND/plays/c34a88cd-6e5d-4072-98f8-1c8bb7103e6f.xml" type="application/xml"/>
52
+ </links>
53
+ </score>
54
+ <score type="extrapoint" clock="13:32" quarter="2" points="1">
55
+ <summary>
56
+ <![CDATA[5-D.Carpenter extra point is good.]]>
57
+ </summary>
58
+ <links>
59
+ <link rel="summary" href="/2012/REG/9/MIA/IND/plays/3b73e8a4-e44d-4b97-b198-42a2e8954c3c.xml" type="application/xml"/>
60
+ </links>
61
+ </score>
62
+ </drive>
63
+ <drive sequence="4" clock="13:25" quarter="2" team="IND">
64
+ <score type="fieldgoal" clock="09:42" quarter="2" points="3">
65
+ <summary>
66
+ <![CDATA[4-A.Vinatieri 23 yards Field Goal is Good.]]>
67
+ </summary>
68
+ <links>
69
+ <link rel="summary" href="/2012/REG/9/MIA/IND/plays/ceb258a0-ee6e-4b5b-8271-c42af4fa6a72.xml" type="application/xml"/>
70
+ </links>
71
+ </score>
72
+ </drive>
73
+ <drive sequence="5" clock="09:37" quarter="2" team="MIA">
74
+ <score type="touchdown" clock="05:16" quarter="2" points="6">
75
+ <summary>
76
+ <![CDATA[22-R.Bush runs 18 yards for a touchdown.]]>
77
+ </summary>
78
+ <links>
79
+ <link rel="summary" href="/2012/REG/9/MIA/IND/plays/595a0a07-1d75-40d5-9c3c-d52eb8d7f3a6.xml" type="application/xml"/>
80
+ </links>
81
+ </score>
82
+ <score type="extrapoint" clock="05:16" quarter="2" points="1">
83
+ <summary>
84
+ <![CDATA[5-D.Carpenter extra point is good.]]>
85
+ </summary>
86
+ <links>
87
+ <link rel="summary" href="/2012/REG/9/MIA/IND/plays/c9e83168-d56a-434b-8ba2-5673ab571806.xml" type="application/xml"/>
88
+ </links>
89
+ </score>
90
+ </drive>
91
+ </scoring_drives>
92
+ </game>
93
+ <!-- Generation finished at Sun Nov 04 19:18:24 +0000 2012 -->
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sports_data_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -191,8 +191,9 @@ files:
191
191
  - lib/sports_data_api.rb
192
192
  - lib/sports_data_api/version.rb
193
193
  - spec/lib/nfl_spec.rb
194
+ - spec/lib/sports_data_api_spec.rb
194
195
  - spec/spec_helper.rb
195
- - spec/xml/game.xml
196
+ - spec/xml/boxscore.xml
196
197
  - spec/xml/schedule.xml
197
198
  - spec/xml/teams.xml
198
199
  - sports_data_api.gemspec
@@ -210,7 +211,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
210
211
  version: '0'
211
212
  segments:
212
213
  - 0
213
- hash: -1347555009981213205
214
+ hash: 3259236789151721605
214
215
  required_rubygems_version: !ruby/object:Gem::Requirement
215
216
  none: false
216
217
  requirements:
@@ -219,7 +220,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
219
220
  version: '0'
220
221
  segments:
221
222
  - 0
222
- hash: -1347555009981213205
223
+ hash: 3259236789151721605
223
224
  requirements: []
224
225
  rubyforge_project:
225
226
  rubygems_version: 1.8.24
@@ -231,7 +232,8 @@ summary: SportsData’s comprehensive data coverage includes all major U.S. spor
231
232
  from years of experience.
232
233
  test_files:
233
234
  - spec/lib/nfl_spec.rb
235
+ - spec/lib/sports_data_api_spec.rb
234
236
  - spec/spec_helper.rb
235
- - spec/xml/game.xml
237
+ - spec/xml/boxscore.xml
236
238
  - spec/xml/schedule.xml
237
239
  - spec/xml/teams.xml
data/spec/xml/game.xml DELETED
@@ -1,69 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <!-- Generation started at Fri Nov 02 02:27:02 +0000 2012 -->
3
- <game xmlns="http://feed.elasticstats.com/schema/nfl/boxscore-v1.0.xsd" id="82748625-c24e-437a-b991-cab7f766c249" scheduled="2012-11-02T00:20:00+00:00" home="SD" away="KC" status="inprogress" quarter="3" clock=":53">
4
- <team id="SD" name="Chargers" market="San Diego" remaining_challenges="2" remaining_timeouts="3">
5
- <scoring points="10">
6
- <quarter number="1" points="7"/>
7
- <quarter number="2" points="3"/>
8
- <quarter number="3" points="0"/>
9
- </scoring>
10
- </team>
11
- <team id="KC" name="Chiefs" market="Kansas City" remaining_challenges="2" remaining_timeouts="3">
12
- <scoring points="6">
13
- <quarter number="1" points="0"/>
14
- <quarter number="2" points="3"/>
15
- <quarter number="3" points="3"/>
16
- </scoring>
17
- </team>
18
- <scoring_drives>
19
- <drive sequence="1" clock="15:00" quarter="1" team="SD">
20
- <score type="touchdown" clock="10:31" quarter="1" points="6">
21
- <summary>
22
- <![CDATA[17-P.Rivers complete to 85-A.Gates. 85-A.Gates runs 14 yards for a touchdown.]]>
23
- </summary>
24
- <links>
25
- <link rel="summary" href="/2012/REG/9/KC/SD/plays/fb5c3b6f-be0a-4f3f-819e-f1134204e312.xml" type="application/xml"/>
26
- </links>
27
- </score>
28
- <score type="extrapoint" clock="10:24" quarter="1" points="1">
29
- <summary>
30
- <![CDATA[9-N.Novak extra point is good.]]>
31
- </summary>
32
- <links>
33
- <link rel="summary" href="/2012/REG/9/KC/SD/plays/cecb31f7-febb-470d-b833-b32b9411fa95.xml" type="application/xml"/>
34
- </links>
35
- </score>
36
- </drive>
37
- <drive sequence="2" clock="02:18" quarter="1" team="SD">
38
- <score type="fieldgoal" clock="09:13" quarter="2" points="3">
39
- <summary>
40
- <![CDATA[9-N.Novak 25 yards Field Goal is Good.]]>
41
- </summary>
42
- <links>
43
- <link rel="summary" href="/2012/REG/9/KC/SD/plays/2036be2d-f58b-4290-9e45-2e171c37588e.xml" type="application/xml"/>
44
- </links>
45
- </score>
46
- </drive>
47
- <drive sequence="3" clock="09:10" quarter="2" team="KC">
48
- <score type="fieldgoal" clock="02:56" quarter="2" points="3">
49
- <summary>
50
- <![CDATA[6-R.Succop 49 yards Field Goal is Good.]]>
51
- </summary>
52
- <links>
53
- <link rel="summary" href="/2012/REG/9/KC/SD/plays/68de7467-99b7-4e87-939d-7dc9b90c0462.xml" type="application/xml"/>
54
- </links>
55
- </score>
56
- </drive>
57
- <drive sequence="4" clock="07:09" quarter="3" team="KC">
58
- <score type="fieldgoal" clock=":58" quarter="3" points="3">
59
- <summary>
60
- <![CDATA[6-R.Succop 41 yards Field Goal is Good.]]>
61
- </summary>
62
- <links>
63
- <link rel="summary" href="/2012/REG/9/KC/SD/plays/35b31551-62ce-430b-8d1e-4153a1e81483.xml" type="application/xml"/>
64
- </links>
65
- </score>
66
- </drive>
67
- </scoring_drives>
68
- </game>
69
- <!-- Generation finished at Fri Nov 02 02:27:02 +0000 2012 -->