sports_data_api 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/nfl.rb +60 -1
- data/lib/sports_data_api/version.rb +1 -1
- data/lib/sports_data_api.rb +10 -2
- data/spec/lib/nfl_spec.rb +58 -0
- data/spec/lib/sports_data_api_spec.rb +18 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/xml/boxscore.xml +93 -0
- metadata +7 -5
- data/spec/xml/game.xml +0 -69
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.
|
data/lib/sports_data_api.rb
CHANGED
@@ -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
@@ -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.
|
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/
|
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:
|
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:
|
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/
|
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 -->
|