mlb_gameday 0.0.11 → 0.1.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 05cb0963a6f9526bd2c8f340327d3c94d84ae327
4
- data.tar.gz: 41ec430d36c0b420764f404023f57370196d3d78
3
+ metadata.gz: 2ce56fe941c7aa4f12153197768ee98e687f92b6
4
+ data.tar.gz: 44b99fa141ae3ef58ba69789265546d3bc7dc7d9
5
5
  SHA512:
6
- metadata.gz: 5662712aa5ccce3ba76f4d496c247a023658e3f822c11a6ab44f98a4334949f0217e11c2dcb5c1beced7653270516373fd96ad21718814c0a9f3b9ae6241adc6
7
- data.tar.gz: 592dd76a7351cd360a3838393791a41590354bd87e35e3518d83603bec32fad27392547f5332335398393dffe87a25b6270ec39a53eb82b182a65b9daee871b9
6
+ metadata.gz: f19a6879750da08a088288a2a940b5cb30fe5b7cfaa8fe0128760c993a4d2478f1ab3ef35ff3e015afcf79915f278417a2cfaa650a4a83c69fb4c0834b00d9f9
7
+ data.tar.gz: d7e4c7d2068db64398847a2e61823bfc22c344a584b07646a113e4e13c5fdd2c836acc6e7a78c1302ad77b2d3f0dab9c7bee03b13d9f68956388ff88040496aa
data/.rubocop.yml ADDED
@@ -0,0 +1,19 @@
1
+ AllCops:
2
+ Include:
3
+ - Rakefile
4
+ - Gemfile
5
+
6
+ Metrics/AbcSize:
7
+ Enabled: false
8
+
9
+ Metrics/ClassLength:
10
+ Max: 100
11
+
12
+ Metrics/CyclomaticComplexity:
13
+ Enabled: false
14
+
15
+ Metrics/MethodLength:
16
+ Max: 15
17
+
18
+ Style/Documentation:
19
+ Enabled: false
data/Rakefile CHANGED
@@ -1 +1,6 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
data/lib/mlb_gameday.rb CHANGED
@@ -3,157 +3,151 @@ require 'nokogiri'
3
3
  require 'open-uri'
4
4
  require 'yaml'
5
5
 
6
- %w{version league division team game player pitcher batter}.each do |file|
7
- require "mlb_gameday/#{file}"
6
+ %w(version league division team game player pitcher batter).each do |file|
7
+ require "mlb_gameday/#{file}"
8
8
  end
9
9
 
10
10
  module MLBGameday
11
- API_URL = "http://gd2.mlb.com/components/game/mlb"
12
-
13
- class API
14
- def initialize
15
- # File File File File File File File File File File File File File File File
16
- @leagues = YAML.load File.open(File.join(File.dirname(File.expand_path(__FILE__)), '../resources/data.yml'))
17
- end
18
-
19
- def leagues
20
- @leagues
21
- end
22
-
23
- def league(name)
24
- return name if name.is_a? MLBGameday::League
25
-
26
- @leagues[name]
27
- end
28
-
29
- def team(name)
30
- return name if name.is_a? MLBGameday::Team
31
-
32
- teams.each do |team|
33
- return team if team.names.include? name.downcase
34
- end
35
-
36
- nil
37
- end
38
-
39
- def teams
40
- @teams ||= divisions.map(&:teams).map(&:values).flatten
41
- end
42
-
43
- def division(league, name)
44
- @leagues[league][name]
45
- end
46
-
47
- def divisions
48
- @divisions ||= @leagues[:AL].divisions.values + @leagues[:NL].divisions.values
49
- end
50
-
51
- def pitcher(id)
52
- return nil if id.empty?
11
+ API_URL = 'http://gd2.mlb.com/components/game/mlb'
53
12
 
54
- MLBGameday::Pitcher.new(self, id, fetch_pitcher_xml(id))
55
- end
13
+ BATTER = '/year_%{year}/batters/%{id}'
14
+ PITCHER = '/year_%{year}/pitchers/%{id}'
15
+ BOXSCORE = '/year_%{year}/month_%{month}/day_%{day}/gid_%{gid}/boxscore'
16
+ GAMECENTER = '/year_%{year}/month_%{month}/day_%{day}/gid_%{gid}/gamecenter'
17
+ LINESCORE = '/year_%{year}/month_%{month}/day_%{day}/gid_%{gid}/linescore'
18
+ SCOREBOARD = '/year_%Y/month_%m/day_%d/miniscoreboard'
56
19
 
57
- def batter(id)
58
- return nil if id.empty?
59
-
60
- MLBGameday::Batter.new(self, id, fetch_batter_xml(id))
61
- end
62
-
63
- def game(gid)
64
- MLBGameday::Game.new(
65
- self,
66
- gid,
67
- gamecenter: fetch_gamecenter_xml(gid),
68
- linescore: fetch_linescore_xml(gid),
69
- boxscore: fetch_boxscore_xml(gid)
70
- )
71
- end
72
-
73
- def find_games(team: nil, date: nil)
74
- date = Date.today if date.nil?
75
-
76
- doc = fetch_scoreboard_xml(date)
77
-
78
- if team.nil?
79
- doc.xpath("//games/game").map do |game|
80
- gid = game.xpath("@gameday_link").first.value
81
-
82
- MLBGameday::Game.new(
83
- self,
84
- gid,
85
- gamecenter: fetch_gamecenter_xml(gid),
86
- linescore: fetch_linescore_xml(gid),
87
- boxscore: fetch_boxscore_xml(gid)
88
- )
89
- end
90
- else
91
- team = team(team)
92
-
93
- doc.xpath("//games/game").map do |game|
94
- if [game.xpath("@home_name_abbrev").first.value, game.xpath("@away_name_abbrev").first.value].include? team.code
95
- gid = game.xpath("@gameday_link").first.value
96
-
97
- MLBGameday::Game.new(
98
- self,
99
- gid,
100
- gamecenter: fetch_gamecenter_xml(gid),
101
- linescore: fetch_linescore_xml(gid),
102
- boxscore: fetch_boxscore_xml(gid),
103
- )
104
- end
105
- end.compact!
106
- end
107
- end
108
-
109
- def fetch_scoreboard_xml(date)
110
- Nokogiri::XML(open(API_URL + date.strftime("/year_%Y/month_%m/day_%d/miniscoreboard.xml")))
111
- end
20
+ class API
21
+ attr_reader :leagues
22
+
23
+ def initialize
24
+ @leagues = YAML.load File.open File.join(
25
+ File.dirname(File.expand_path __FILE__), '../resources/data.yml'
26
+ )
27
+ end
112
28
 
113
- def fetch_linescore_xml(gid)
114
- year, month, day, _ = gid.split("_")
115
-
116
- Nokogiri::XML(open(API_URL + "/year_#{ year }/month_#{ month }/day_#{ day }/gid_#{ gid }/linescore.xml"))
117
- end
29
+ def league(name)
30
+ return name if name.is_a? MLBGameday::League
118
31
 
119
- def fetch_boxscore_xml(gid)
120
- year, month, day, _ = gid.split("_")
32
+ @leagues[name]
33
+ end
34
+
35
+ def team(name)
36
+ return name if name.is_a? MLBGameday::Team
121
37
 
122
- Nokogiri::XML(open(API_URL + "/year_#{ year }/month_#{ month }/day_#{ day }/gid_#{ gid }/boxscore.xml"))
123
- rescue
124
- nil
125
- end
126
-
127
- def fetch_gamecenter_xml(gid)
128
- year, month, day, _ = gid.split("_")
129
-
130
- Nokogiri::XML(open(API_URL + "/year_#{ year }/month_#{ month }/day_#{ day }/gid_#{ gid }/gamecenter.xml"))
131
- rescue
132
- nil
133
- end
134
-
135
- def fetch_batter_xml(id, year: nil)
136
- year = Date.today.year if year.nil?
137
-
138
- # We only really want one piece of data from this file...
139
- year_data = Nokogiri::XML(open(API_URL + "/year_#{ year }/batters/#{ id }.xml"))
140
-
141
- gid = year_data.xpath("//pitching/@game_id").first.value
142
- year, month, day, _ = gid.split("/")
143
-
144
- Nokogiri::XML(open(MLBGameday::API_URL + "/year_#{ year }/month_#{ month }/day_#{ day }/gid_#{ gid.gsub(/[^a-z0-9]/, "_") }/batters/#{ id }.xml"))
145
- end
146
-
147
- def fetch_pitcher_xml(id, year: nil)
148
- year = Date.today.year if year.nil?
149
-
150
- # We only really want one piece of data from this file...
151
- year_data = Nokogiri::XML(open(API_URL + "/year_#{ year }/pitchers/#{ id }.xml"))
152
-
153
- gid = year_data.xpath("//pitching/@game_id").first.value
154
- year, month, day, _ = gid.split("/")
155
-
156
- Nokogiri::XML(open(MLBGameday::API_URL + "/year_#{ year }/month_#{ month }/day_#{ day }/gid_#{ gid.gsub(/[^a-z0-9]/, "_") }/pitchers/#{ id }.xml"))
157
- end
158
- end
38
+ teams.each do |team|
39
+ return team if team.names.include? name.downcase
40
+ end
41
+
42
+ nil
43
+ end
44
+
45
+ def teams
46
+ @teams ||= divisions.map(&:teams).map(&:values).flatten
47
+ end
48
+
49
+ def division(league, name)
50
+ @leagues[league][name]
51
+ end
52
+
53
+ def divisions
54
+ @divisions ||= @leagues[:AL].divisions.values +
55
+ @leagues[:NL].divisions.values
56
+ end
57
+
58
+ def pitcher(id)
59
+ return nil if id.empty?
60
+
61
+ MLBGameday::Pitcher.new id: id, xml: pitcher_xml(id)
62
+ end
63
+
64
+ def batter(id)
65
+ return nil if id.empty?
66
+
67
+ MLBGameday::Batter.new id: id, xml: batter_xml(id)
68
+ end
69
+
70
+ def game(gid)
71
+ MLBGameday::Game.new(
72
+ self,
73
+ gid,
74
+ gamecenter: gamecenter_xml(gid),
75
+ linescore: linescore_xml(gid),
76
+ boxscore: boxscore_xml(gid)
77
+ )
78
+ end
79
+
80
+ def find_games(team: nil, date: nil)
81
+ doc = scoreboard_xml(date || Date.today)
82
+
83
+ if team
84
+ code = team(team).code
85
+
86
+ doc.xpath('//games/game').map do |game|
87
+ next unless [game.xpath('@home_name_abbrev').text,
88
+ game.xpath('@away_name_abbrev').text].include? code
89
+
90
+ game game.xpath('@gameday_link').text
91
+ end.compact!
92
+ else
93
+ doc.xpath('//games/game').map do |game|
94
+ game game.xpath('@gameday_link').to_s
95
+ end
96
+ end
97
+ end
98
+
99
+ def scoreboard_xml(date)
100
+ fetch_xml date.strftime SCOREBOARD
101
+ end
102
+
103
+ def linescore_xml(gid)
104
+ year, month, day, _ = gid.split '_'
105
+
106
+ fetch_xml LINESCORE, year: year, month: month, day: day, gid: gid
107
+ end
108
+
109
+ def boxscore_xml(gid)
110
+ year, month, day, _ = gid.split '_'
111
+
112
+ fetch_xml BOXSCORE, year: year, month: month, day: day, gid: gid
113
+ rescue
114
+ nil
115
+ end
116
+
117
+ def gamecenter_xml(gid)
118
+ year, month, day, _ = gid.split '_'
119
+
120
+ fetch_xml GAMECENTER, year: year, month: month, day: day, gid: gid
121
+ rescue
122
+ nil
123
+ end
124
+
125
+ def batter_xml(id, year: nil)
126
+ # We only really want one piece of data from this file...
127
+ year_data = fetch_xml BATTER, id: id, year: (year || Date.today.year)
128
+
129
+ gid = year_data.xpath('//batting/@game_id').text
130
+ year, month, day, _ = gid.split '/'
131
+
132
+ fetch_xml "/year_#{year}/month_#{month}/day_#{day}/" \
133
+ "gid_#{gid.gsub(/[^a-z0-9]/, '_')}/batters/#{id}"
134
+ end
135
+
136
+ def pitcher_xml(id, year: nil)
137
+ # We only really want one piece of data from this file...
138
+ year_data = fetch_xml PITCHER, id: id, year: (year || Date.today.year)
139
+
140
+ gid = year_data.xpath('//pitching/@game_id').text
141
+ year, month, day, _ = gid.split '/'
142
+
143
+ fetch_xml "/year_#{year}/month_#{month}/day_#{day}/" \
144
+ "gid_#{gid.gsub(/[^a-z0-9]/, '_')}/pitchers/#{id}"
145
+ end
146
+
147
+ protected
148
+
149
+ def fetch_xml(path, interpolations = {})
150
+ Nokogiri::XML open format(API_URL + path + '.xml', interpolations)
151
+ end
152
+ end
159
153
  end
@@ -1,4 +1,4 @@
1
1
  module MLBGameday
2
- class Batter < Player
3
- end
2
+ class Batter < Player
3
+ end
4
4
  end
@@ -1,21 +1,12 @@
1
1
  module MLBGameday
2
- class Division
3
- def initialize(league, name, teams)
4
- @league = league
5
- @name = name
6
- @teams = teams
7
- end
2
+ class Division
3
+ attr_reader :league, :name, :teams
8
4
 
9
- def league
10
- @league
11
- end
12
-
13
- def name
14
- @name
15
- end
16
-
17
- def teams
18
- @teams
19
- end
20
- end
5
+ def initialize(id:, league:, name:, teams:)
6
+ @id = id
7
+ @league = league
8
+ @name = name
9
+ @teams = teams
10
+ end
11
+ end
21
12
  end
@@ -1,227 +1,218 @@
1
1
  module MLBGameday
2
- class Game
3
- def initialize(api, gid, linescore: nil, gamecenter: nil, boxscore: nil)
4
- @api = api
5
- @gid = gid
6
-
7
- @linescore = linescore
8
- @gamecenter = gamecenter
9
- @boxscore = boxscore
10
-
11
- @home = @api.team(linescore.xpath("//game/@home_name_abbrev").first.value)
12
- @away = @api.team(linescore.xpath("//game/@away_name_abbrev").first.value)
13
- end
14
-
15
- def gid
16
- @gid
17
- end
18
-
19
- def teams
20
- [@home, @away]
21
- end
22
-
23
- def home_team
24
- @home
25
- end
26
-
27
- def away_team
28
- @away
29
- end
30
-
31
- def venue
32
- @linescore.xpath("//game/@venue").first.value
33
- end
34
-
35
- def home_start_time(ampm: true)
36
- if ampm
37
- "#{ @linescore.xpath("//game/@home_time").first.value } #{ @linescore.xpath("//game/@home_ampm").first.value } #{ @linescore.xpath("//game/@home_time_zone").first.value }"
38
- else
39
- "#{ @linescore.xpath("//game/@home_time").first.value } #{ @linescore.xpath("//game/@home_time_zone").first.value }"
40
- end
41
- end
42
-
43
- def away_start_time(ampm: true)
44
- if ampm
45
- "#{ @linescore.xpath("//game/@away_time").first.value } #{ @linescore.xpath("//game/@away_ampm").first.value } #{ @linescore.xpath("//game/@away_time_zone").first.value }"
46
- else
47
- "#{ @linescore.xpath("//game/@away_time").first.value } #{ @linescore.xpath("//game/@away_time_zone").first.value }"
48
- end
49
- end
50
-
51
- # Preview, Pre-Game, In Progress, Final
52
- def status
53
- @status ||= @linescore.xpath("//game/@status").first.value
54
- end
55
-
56
- # [3, Top/Middle/Bottom/End]
57
- def inning
58
- return [0, '?'] if @linescore.xpath("//game/@inning").nil?
59
-
60
- [@linescore.xpath("//game/@inning").first.value.to_i, @linescore.xpath("//game/@inning_state").first.value]
61
- end
62
-
63
- def runners
64
- first, second, third = [nil, nil, nil]
65
-
66
- [first, second, third]
67
- end
68
-
69
- def over?
70
- status == "Final" || status == "Game Over"
71
- end
72
- alias_method :fat_lady_has_sung?, :over?
73
-
74
- def in_progress?
75
- status == "In Progress"
76
- end
77
-
78
- def home_record
79
- [@linescore.xpath("//game/@home_win").first.value, @linescore.xpath("//game/@home_loss").first.value].map(&:to_i)
80
- end
81
-
82
- def away_record
83
- [@linescore.xpath("//game/@away_win").first.value, @linescore.xpath("//game/@away_loss").first.value].map(&:to_i)
84
- end
85
-
86
- def current_pitcher
87
- return nil if !in_progress?
88
-
89
- @api.pitcher @linescore.xpath("//game/current_pitcher/@id").first.value
90
- end
91
-
92
- def opposing_pitcher
93
- return nil if !in_progress?
94
-
95
- @api.pitcher @linescore.xpath("//game/opposing_pitcher/@id").first.value
96
- end
97
-
98
- def winning_pitcher
99
- return nil if !over?
100
-
101
- @api.pitcher @linescore.xpath("//game/winning_pitcher/@id").first.value
102
- end
103
-
104
- def losing_pitcher
105
- return nil if !over?
106
-
107
- @api.pitcher @linescore.xpath("//game/losing_pitcher/@id").first.value
108
- end
109
-
110
- def save_pitcher
111
- return nil if !over?
112
-
113
- @api.pitcher @linescore.xpath("//game/save_pitcher/@id").first.value
114
- end
115
-
116
- def score
117
- return [0, 0] if !in_progress? && !over?
118
-
119
- [@linescore.xpath("//game/@home_team_runs").first.value, @linescore.xpath("//game/@away_team_runs").first.value].map(&:to_i)
120
- end
121
-
122
- def home_pitcher
123
- case status
124
- when "In Progress"
125
- # The xpath changes based on which half of the inning it is
126
- if @linescore.xpath("//game/@top_inning").first.value == "Y"
127
- opposing_pitcher
128
- else
129
- current_pitcher
130
- end
131
- when "Preview", "Warmup", "Pre-Game"
132
- @api.pitcher @linescore.xpath("//game/home_probable_pitcher/@id").first.value
133
- when "Final"
134
- home, away = score
135
-
136
- if home > away
137
- winning_pitcher
138
- elsif away > home
139
- losing_pitcher
140
- else
141
- # Spring training games can end in ties, in which case there's really no pitching data
142
- # See: http://gd2.mlb.com/components/game/mlb/year_2013/month_03/day_07/gid_2013_03_07_texmlb_lanmlb_1/linescore.xml
143
- # This should really give a null object pitcher back
144
- nil
145
- end
146
- else
147
- end
148
- end
149
-
150
- def away_pitcher
151
- case status
152
- when "In Progress"
153
- # The xpath changes based on which half of the inning it is
154
- if @linescore.xpath("//game/@top_inning").first.value == "Y"
155
- current_pitcher
156
- else
157
- opposing_pitcher
158
- end
159
- when "Preview", "Warmup", "Pre-Game"
160
- @api.pitcher @linescore.xpath("//game/away_probable_pitcher/@id").first.value
161
- when "Final", "Game Over"
162
- home, away = score
163
-
164
- if home > away
165
- losing_pitcher
166
- elsif away > home
167
- winning_pitcher
168
- else
169
- # Spring training games can end in ties, in which case there's really no pitching data
170
- # See: http://gd2.mlb.com/components/game/mlb/year_2013/month_03/day_07/gid_2013_03_07_texmlb_lanmlb_1/linescore.xml
171
- # This should really give a null object pitcher back
172
- nil
173
- end
174
- else
175
- end
176
- end
177
-
178
- def home_tv
179
- return nil if !@gamecenter
180
-
181
- @gamecenter.xpath("//game/broadcast/home/tv").first.content
182
- end
183
-
184
- def away_tv
185
- return nil if !@gamecenter
186
-
187
- @gamecenter.xpath("//game/broadcast/away/tv").first.content
188
- end
189
-
190
- def home_radio
191
- return nil if !@gamecenter
192
-
193
- @gamecenter.xpath("//game/broadcast/home/radio").first.content
194
- end
195
-
196
- def away_radio
197
- return nil if !@gamecenter
198
-
199
- @gamecenter.xpath("//game/broadcast/away/radio").first.content
200
- end
201
-
202
- def is_free?
203
- @linescore.xpath("//game/game_media/media/@free").first.value == "ALL"
204
- end
205
-
206
- def date
207
- @date ||= DateTime.strptime(@linescore.xpath("//game/@original_date").first.value, '%Y/%m/%d').to_date
208
- end
209
-
210
- def linescore
211
- @linescore
212
- end
213
-
214
- def gamecenter
215
- @gamecenter
216
- end
217
-
218
- def boxscore
219
- @boxscore
220
- end
221
-
222
- # So we don't get huge printouts
223
- def inspect
224
- %Q{#<MLBGameday::Game @gid="#{@gid}">}
225
- end
226
- end
2
+ # This class is just too long. It might be able to be split up, but it's not
3
+ # likely to happen any time soon. For now, we'll disable the cop.
4
+ # rubocop:disable Metrics/ClassLength
5
+ class Game
6
+ attr_reader :gid, :home_team, :away_team, :linescore, :gamecenter, :boxscore
7
+
8
+ def initialize(api, gid, linescore: nil, gamecenter: nil, boxscore: nil)
9
+ @api = api
10
+ @gid = gid
11
+
12
+ @linescore = linescore
13
+ @gamecenter = gamecenter
14
+ @boxscore = boxscore
15
+
16
+ @home_team = @api.team linescore.xpath('//game/@home_name_abbrev').text
17
+ @away_team = @api.team linescore.xpath('//game/@away_name_abbrev').text
18
+ end
19
+
20
+ def teams
21
+ [@home_team, @away_team]
22
+ end
23
+
24
+ def venue
25
+ @linescore.xpath('//game/@venue').text
26
+ end
27
+
28
+ def home_start_time(ampm: true)
29
+ if ampm
30
+ [
31
+ @linescore.xpath('//game/@home_time').text,
32
+ @linescore.xpath('//game/@home_ampm').text,
33
+ @linescore.xpath('//game/@home_time_zone').text
34
+ ].join ' '
35
+ else
36
+ [
37
+ @linescore.xpath('//game/@home_time').text,
38
+ @linescore.xpath('//game/@home_time_zone').text
39
+ ].join ' '
40
+ end
41
+ end
42
+
43
+ def away_start_time(ampm: true)
44
+ if ampm
45
+ [
46
+ @linescore.xpath('//game/@away_time').text,
47
+ @linescore.xpath('//game/@away_ampm').text,
48
+ @linescore.xpath('//game/@away_time_zone').text
49
+ ].join ' '
50
+ else
51
+ [
52
+ @linescore.xpath('//game/@away_time').text,
53
+ @linescore.xpath('//game/@away_time_zone').text
54
+ ].join ' '
55
+ end
56
+ end
57
+
58
+ # Preview, Pre-Game, In Progress, Final
59
+ def status
60
+ @status ||= @linescore.xpath('//game/@status').text
61
+ end
62
+
63
+ # [3, Top/Middle/Bottom/End]
64
+ def inning
65
+ return [0, '?'] unless @linescore.xpath('//game/@inning')
66
+
67
+ [@linescore.xpath('//game/@inning').text.to_i,
68
+ @linescore.xpath('//game/@inning_state').text]
69
+ end
70
+
71
+ def runners
72
+ first, second, third = [nil, nil, nil]
73
+
74
+ [first, second, third]
75
+ end
76
+
77
+ def over?
78
+ ['Final', 'Game Over', 'Completed Early'].include? status
79
+ end
80
+ alias_method :fat_lady_has_sung?, :over?
81
+
82
+ def in_progress?
83
+ status == 'In Progress'
84
+ end
85
+
86
+ def home_record
87
+ [@linescore.xpath('//game/@home_win'),
88
+ @linescore.xpath('//game/@home_loss')].map(&:text).map(&:to_i)
89
+ end
90
+
91
+ def away_record
92
+ [@linescore.xpath('//game/@away_win'),
93
+ @linescore.xpath('//game/@away_loss')].map(&:text).map(&:to_i)
94
+ end
95
+
96
+ def current_pitcher
97
+ return nil unless in_progress?
98
+
99
+ @api.pitcher @linescore.xpath('//game/current_pitcher/@id').text
100
+ end
101
+
102
+ def opposing_pitcher
103
+ return nil unless in_progress?
104
+
105
+ @api.pitcher @linescore.xpath('//game/opposing_pitcher/@id').text
106
+ end
107
+
108
+ def winning_pitcher
109
+ return nil unless over?
110
+
111
+ @api.pitcher @linescore.xpath('//game/winning_pitcher/@id').text
112
+ end
113
+
114
+ def losing_pitcher
115
+ return nil unless over?
116
+
117
+ @api.pitcher @linescore.xpath('//game/losing_pitcher/@id').text
118
+ end
119
+
120
+ def save_pitcher
121
+ return nil unless over?
122
+
123
+ @api.pitcher @linescore.xpath('//game/save_pitcher/@id').text
124
+ end
125
+
126
+ def away_starting_pitcher
127
+ @linescore.xpath('//game/away_probable_pitcher/@id').text
128
+ end
129
+
130
+ def home_starting_pitcher
131
+ @linescore.xpath('//game/home_probable_pitcher/@id').text
132
+ end
133
+
134
+ def score
135
+ return [0, 0] unless in_progress? || over?
136
+
137
+ [@linescore.xpath('//game/@home_team_runs').text,
138
+ @linescore.xpath('//game/@away_team_runs').text].map(&:to_i)
139
+ end
140
+
141
+ def home_pitcher
142
+ # Spring training games can end in ties, in which case there's
143
+ # really no pitching data. This should really return a null object.
144
+ case status
145
+ when 'In Progress'
146
+ # The xpath changes based on which half of the inning it is
147
+ if @linescore.xpath('//game/@top_inning').text == 'Y'
148
+ opposing_pitcher
149
+ else
150
+ current_pitcher
151
+ end
152
+ when 'Preview', 'Warmup', 'Pre-Game'
153
+ @api.pitcher home_starting_pitcher
154
+ when 'Final'
155
+ home, away = score
156
+
157
+ home > away ? winning_pitcher : losing_pitcher
158
+ end
159
+ end
160
+
161
+ def away_pitcher
162
+ # Spring training games can end in ties, in which case there's
163
+ # really no pitching data. This should really return a null object.
164
+ case status
165
+ when 'In Progress'
166
+ # The xpath changes based on which half of the inning it is
167
+ if @linescore.xpath('//game/@top_inning').text == 'Y'
168
+ current_pitcher
169
+ else
170
+ opposing_pitcher
171
+ end
172
+ when 'Preview', 'Warmup', 'Pre-Game'
173
+ @api.pitcher away_starting_pitcher
174
+ when 'Final', 'Game Over'
175
+ home, away = score
176
+
177
+ home > away ? losing_pitcher : winning_pitcher
178
+ end
179
+ end
180
+
181
+ def home_tv
182
+ return nil unless @gamecenter
183
+
184
+ @gamecenter.xpath('//game/broadcast/home/tv').text
185
+ end
186
+
187
+ def away_tv
188
+ return nil unless @gamecenter
189
+
190
+ @gamecenter.xpath('//game/broadcast/away/tv').text
191
+ end
192
+
193
+ def home_radio
194
+ return nil unless @gamecenter
195
+
196
+ @gamecenter.xpath('//game/broadcast/home/radio').text
197
+ end
198
+
199
+ def away_radio
200
+ return nil unless @gamecenter
201
+
202
+ @gamecenter.xpath('//game/broadcast/away/radio').text
203
+ end
204
+
205
+ def free?
206
+ @linescore.xpath('//game/game_media/media/@free').text == 'ALL'
207
+ end
208
+
209
+ def date
210
+ @date ||= Chronic.parse @linescore.xpath('//game/@original_date').text
211
+ end
212
+
213
+ # So we don't get huge printouts
214
+ def inspect
215
+ %(#<MLBGameday::Game @gid="#{@gid}">)
216
+ end
217
+ end
227
218
  end