mlb_terminal 0.0.2 → 0.0.3
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/Gemfile.lock +1 -1
- data/README.md +38 -10
- data/bin/mlb +57 -11
- data/lib/mlb_terminal.rb +1 -1
- data/lib/mlb_terminal/game.rb +153 -0
- data/lib/mlb_terminal/version.rb +1 -1
- data/mlb_terminal.gemspec +2 -2
- metadata +6 -5
- data/lib/mlb_terminal/client.rb +0 -85
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -9,22 +9,23 @@ Don't you just wish you could have a little terminal app to stream out real-time
|
|
9
9
|
### Syntax
|
10
10
|
|
11
11
|
#### Commands
|
12
|
-
|
13
|
-
* help: Display global or [command] help documentation.
|
14
|
-
*
|
12
|
+
|
13
|
+
* help: Display global or [command] help documentation.
|
14
|
+
* games: Print out a list of scheduled games for the specified date
|
15
|
+
* game: Print out play-by-play events for a specific game. Use `--pitches` to output realtime pitch trajectory data.
|
15
16
|
|
16
17
|
#### Global options
|
17
|
-
|
18
|
+
|
18
19
|
* -h, --help: Display help documentation
|
19
|
-
|
20
|
+
|
20
21
|
* -v, --version: Display version information
|
21
|
-
|
22
|
+
|
22
23
|
* -t, --trace: Display backtrace when an error occurs
|
23
24
|
|
24
25
|
### Examples
|
25
26
|
|
26
27
|
> # List todays games
|
27
|
-
> mlb
|
28
|
+
> mlb games
|
28
29
|
0 Red Sox (69-88) @ Orioles (90-67) 7:05 ET (F) 1-9
|
29
30
|
1 Reds (95-62) @ Pirates (76-81) 7:05 ET (F) 1-0
|
30
31
|
2 Royals (70-87) @ Indians (66-91) 7:05 ET (F) 5-8
|
@@ -41,6 +42,33 @@ Don't you just wish you could have a little terminal app to stream out real-time
|
|
41
42
|
13 Giants (92-65) @ Padres (74-83) 10:05 ET (F) 3-1
|
42
43
|
14 Rockies (62-95) @ Dodgers (82-75) 10:10 ET (F) 0-8
|
43
44
|
|
44
|
-
# How did the Nationals do on
|
45
|
-
> mlb
|
46
|
-
Nationals (29-21) @ Marlins (29-22)
|
45
|
+
# How did the Nationals do on 5/30/2012?
|
46
|
+
> mlb games --date 2012-05-30 | grep -i nationals | cut -f 2,4
|
47
|
+
Nationals (29-21) @ Marlins (29-22) 3-5
|
48
|
+
|
49
|
+
> # How did Bryce Harper do tonight?
|
50
|
+
> mlb games | grep Nationals | cut -f 1 | xargs mlb game | grep Harper
|
51
|
+
2012-09-29 19:18:00 1 2 1/2/1 Bryce Harper singles on a soft line drive to center fielder Jon Jay.
|
52
|
+
2012-09-29 19:20:11 1 3 1/2/1 Ryan Zimmerman doubles (36) on a fly ball to left fielder Matt Holliday. Bryce Harper to 3rd.
|
53
|
+
2012-09-29 19:26:56 1 5 0/0/1 Play reviewed and overturned: Michael Morse hits a grand slam (17) to right field. Bryce Harper scores. Ryan Zimmerman scores. Adam LaRoche scores.
|
54
|
+
2012-09-29 19:48:35 2 14 3/2/3 Bryce Harper grounds out, second baseman Skip Schumaker to first baseman Allen Craig.
|
55
|
+
2012-09-29 19:56:08 2 17 3/2/2 Carlos Beltran lines out to center fielder Bryce Harper.
|
56
|
+
2012-09-29 20:09:19 3 23 3/2/1 Pete Kozma flies out to center fielder Bryce Harper.
|
57
|
+
2012-09-29 20:38:38 5 36 3/3/1 Bryce Harper called out on strikes.
|
58
|
+
2012-09-29 21:15:16 7 51 2/2/1 Bryce Harper singles on a line drive to left fielder Matt Holliday.
|
59
|
+
2012-09-29 21:19:08 7 53 1/1/2 Adam LaRoche singles on a sharp line drive to first baseman Allen Craig. Bryce Harper to 3rd.
|
60
|
+
2012-09-29 21:24:34 7 55 0/1/1 Yadier Molina flies out to center fielder Bryce Harper.
|
61
|
+
2012-09-29 21:37:46 7 61 1/2/2 Matt Carpenter flies out to center fielder Bryce Harper.
|
62
|
+
2012-09-29 22:10:49 9 71 1/0/2 Bryce Harper doubles (25) on a line drive to left fielder Matt Holliday.
|
63
|
+
2012-09-29 22:21:20 9 76 0/0/2 Jon Jay out on a sacrifice fly to center fielder Bryce Harper. Pete Kozma scores.
|
64
|
+
|
65
|
+
> # Visualize pitch speed for Gio Gonzalez on his full game on August 8, 2012.
|
66
|
+
> mlb games --date 2012-08-08 \
|
67
|
+
| grep Nationals \
|
68
|
+
| cut -f 1 \
|
69
|
+
| xargs mlb game --pitches --date 2012-08-08 \
|
70
|
+
| awk 'BEGIN{FS="\t"}{ if ($4=="Gio Gonzalez") print}' \
|
71
|
+
| cut -f 1,9,6 \
|
72
|
+
| Rscript -e 'library(ggplot2); library(scales); d <- read.csv("stdin", header=F, sep="\\t", col.names=c("time", "type", "pitch_speed")); png("gio-pitch-speed.png"); ggplot(d, aes(x=as.POSIXct(time), y=pitch_speed, colour=type, shape=type)) + geom_point() + opts(title="Pitch Speed Over Time for Gio Gonzalez") + scale_x_datetime(breaks=date_breaks("1 hour"), minor_breaks=date_breaks("15 min"), labels=date_format("%H:%M")) + scale_colour_discrete(name = "Pitch Type") + scale_shape_discrete(name = "Pitch Type") + xlab("Time") + ylab("Pitch Speed"); dev.off()'
|
73
|
+
> open gio-pitch-speed.png
|
74
|
+

|
data/bin/mlb
CHANGED
@@ -17,7 +17,7 @@ command :games do |c|
|
|
17
17
|
c.option '--date STRING', String, 'List games for specified dates (Default: today)'
|
18
18
|
c.action do |args, options|
|
19
19
|
options.default :date => Time.now.to_date.to_s
|
20
|
-
MLBTerminal::
|
20
|
+
MLBTerminal::Game.list(Date.parse options.date).each_with_index do |game, index|
|
21
21
|
puts [
|
22
22
|
index,
|
23
23
|
"#{game[:away_team][:name]} " \
|
@@ -36,6 +36,7 @@ command :game do |c|
|
|
36
36
|
c.description = 'Print play-by-play action for the corresponding game. Columns: time, inning, balls/strikes/outs/description.'
|
37
37
|
c.example 'description', 'command example'
|
38
38
|
c.option '--date STRING', String, 'Specify the date for the corresponding game number.'
|
39
|
+
c.option '--pitches', 'Print pitch-by-pitch action'
|
39
40
|
c.action do |args, options|
|
40
41
|
options.default :date => Time.now.to_date.to_s
|
41
42
|
|
@@ -47,23 +48,68 @@ command :game do |c|
|
|
47
48
|
end
|
48
49
|
|
49
50
|
game_number = args.first.to_i
|
50
|
-
game_info = MLBTerminal::
|
51
|
+
game_info = MLBTerminal::Game.list(date)[game_number]
|
51
52
|
|
52
53
|
if game_info.nil?
|
53
54
|
puts "Error: Game does not exist"
|
54
55
|
break
|
55
56
|
end
|
56
57
|
|
57
|
-
game = MLBTerminal::
|
58
|
+
game = MLBTerminal::Game.new(game_info[:game_id])
|
58
59
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
60
|
+
begin
|
61
|
+
if options.pitches
|
62
|
+
game.pitches.each do |pitch|
|
63
|
+
puts [
|
64
|
+
pitch[:time].getlocal.strftime("%Y-%m-%d %H:%M:%S"),
|
65
|
+
pitch[:inning],
|
66
|
+
pitch[:inning_loc],
|
67
|
+
pitch[:pitcher],
|
68
|
+
pitch[:batter],
|
69
|
+
pitch[:type],
|
70
|
+
pitch[:x],
|
71
|
+
pitch[:y],
|
72
|
+
pitch[:start_speed],
|
73
|
+
pitch[:end_speed],
|
74
|
+
pitch[:sz_top],
|
75
|
+
pitch[:sz_bot],
|
76
|
+
pitch[:pfx_x],
|
77
|
+
pitch[:pfx_z],
|
78
|
+
pitch[:px],
|
79
|
+
pitch[:pz],
|
80
|
+
pitch[:x0],
|
81
|
+
pitch[:y0],
|
82
|
+
pitch[:z0],
|
83
|
+
pitch[:vx0],
|
84
|
+
pitch[:vy0],
|
85
|
+
pitch[:vz0],
|
86
|
+
pitch[:ax],
|
87
|
+
pitch[:ay],
|
88
|
+
pitch[:az],
|
89
|
+
pitch[:break_y],
|
90
|
+
pitch[:break_angle],
|
91
|
+
pitch[:break_length],
|
92
|
+
pitch[:pitch_type],
|
93
|
+
pitch[:type_confidence],
|
94
|
+
pitch[:zone],
|
95
|
+
pitch[:nasty],
|
96
|
+
pitch[:spin_dir],
|
97
|
+
pitch[:spin_rate],
|
98
|
+
pitch[:cc],
|
99
|
+
pitch[:mt]].join("\t")
|
100
|
+
end
|
101
|
+
else
|
102
|
+
game.events.each do |event|
|
103
|
+
puts [
|
104
|
+
event[:time].getlocal.strftime("%Y-%m-%d %H:%M:%S"),
|
105
|
+
event[:inning],
|
106
|
+
event[:num],
|
107
|
+
"#{event[:balls]}/#{event[:strikes]}/#{event[:outs]}",
|
108
|
+
event[:desc]].join("\t")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
rescue SystemExit, Interrupt
|
112
|
+
# Do nothing if a user issues ctrl-c.
|
66
113
|
end
|
67
114
|
end
|
68
115
|
end
|
69
|
-
|
data/lib/mlb_terminal.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
require 'mlb_terminal/version'
|
2
|
-
require 'mlb_terminal/
|
2
|
+
require 'mlb_terminal/game'
|
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'active_support/core_ext/integer/inflections'
|
5
|
+
|
6
|
+
module MLBTerminal
|
7
|
+
MLB_BASE_URL = 'http://gd2.mlb.com/components/game/mlb'
|
8
|
+
|
9
|
+
class Game
|
10
|
+
def self.list(date = Time.now.to_date)
|
11
|
+
doc = Nokogiri::HTML(open "#{base_url_for_date date}/epg.xml")
|
12
|
+
|
13
|
+
doc.xpath("//epg/game").map{|game|
|
14
|
+
{:home_team => {
|
15
|
+
:name => game["home_team_name"],
|
16
|
+
:wins => game["home_win"],
|
17
|
+
:losses => game["home_loss"]},
|
18
|
+
:away_team => {
|
19
|
+
:name => game["away_team_name"],
|
20
|
+
:wins => game["away_win"],
|
21
|
+
:losses => game["away_loss"]},
|
22
|
+
:score => {
|
23
|
+
:home => game["home_team_runs"],
|
24
|
+
:away => game["away_team_runs"]},
|
25
|
+
:starts => "#{game["time"]} #{game["time_zone"]}",
|
26
|
+
:status => "#{game["status"]}" \
|
27
|
+
"#{game["status"] == "In Progress" ?
|
28
|
+
", #{game["top_inning"]=="Y" ? "Top" : "Bot"} of #{game["inning"].to_i.ordinalize}" :
|
29
|
+
""}",
|
30
|
+
:game_id => game["gameday"]}}
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(gameday)
|
34
|
+
@gameday = gameday
|
35
|
+
year, month, day, game_name = /([0-9]{4})_([0-9]{2})_([0-9]{2})_(.*)/.match(@gameday).to_a.slice(1,4)
|
36
|
+
@base_url = "#{Game.base_url_for_date(Date.new(year.to_i, month.to_i, day.to_i))}/gid_#{@gameday}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def events(delay = 5, &block)
|
40
|
+
last_atbat = 0
|
41
|
+
|
42
|
+
Enumerator.new do |y|
|
43
|
+
begin
|
44
|
+
doc = Nokogiri::HTML(open "#{@base_url}/game_events.xml")
|
45
|
+
|
46
|
+
doc.xpath("//game/inning[*/atbat/@num > #{last_atbat}]").each do |inning|
|
47
|
+
inning.xpath("*/atbat").each do |at_bat|
|
48
|
+
y.yield({
|
49
|
+
:inning => inning["num"],
|
50
|
+
:inning_loc => at_bat.xpath("..").first.name.camelcase,
|
51
|
+
:num => at_bat["num"],
|
52
|
+
:balls => at_bat["b"],
|
53
|
+
:strikes => at_bat["s"],
|
54
|
+
:outs => at_bat["o"],
|
55
|
+
:time => Time.parse(at_bat["start_tfs_zulu"], "%Y-%m-%dT%H:%M:%SZ"),
|
56
|
+
:desc => at_bat["des"].strip})
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
last_atbat = doc.xpath("//game/inning/*/atbat/@num").map(&:value).map(&:to_i).max
|
61
|
+
|
62
|
+
sleep delay
|
63
|
+
|
64
|
+
if doc.xpath("//game").first["ind"] != "F"
|
65
|
+
doc = Nokogiri::HTML(open "#{@base_url}/inning/inning_all.xml")
|
66
|
+
end
|
67
|
+
end while game_status != "F"
|
68
|
+
end.each(&block)
|
69
|
+
end
|
70
|
+
|
71
|
+
def pitches(delay = 5, &block)
|
72
|
+
last_pitch = 0
|
73
|
+
players = player_lookup
|
74
|
+
doc = Nokogiri::HTML(open "#{@base_url}/inning/inning_all.xml")
|
75
|
+
|
76
|
+
Enumerator.new do |y|
|
77
|
+
begin
|
78
|
+
doc.xpath("//game/inning[*/*/pitch/@id > #{last_pitch}]").each do |inning|
|
79
|
+
|
80
|
+
inning.xpath("*/atbat").each do |at_bat|
|
81
|
+
pitcher = players[at_bat["pitcher"]]
|
82
|
+
batter = players[at_bat["batter"]]
|
83
|
+
|
84
|
+
at_bat.xpath("pitch").each do |pitch|
|
85
|
+
y.yield({
|
86
|
+
:time => Time.parse(pitch["tfs_zulu"], "%Y-%m-%dT%H:%M:%SZ"),
|
87
|
+
:inning => inning["num"],
|
88
|
+
:inning_loc => at_bat.xpath("..").first.name.camelcase,
|
89
|
+
:pitcher => pitcher,
|
90
|
+
:batter => batter,
|
91
|
+
:type => pitch["type"],
|
92
|
+
:x => pitch["x"],
|
93
|
+
:y => pitch["y"],
|
94
|
+
:start_speed => pitch["start_speed"],
|
95
|
+
:end_speed => pitch["end_speed"],
|
96
|
+
:sz_top => pitch["sz_top"],
|
97
|
+
:sz_bot => pitch["sz_bot"],
|
98
|
+
:pfx_x => pitch["pfx_x"],
|
99
|
+
:pfx_z => pitch["pfx_z"],
|
100
|
+
:px => pitch["px"],
|
101
|
+
:pz => pitch["pz"],
|
102
|
+
:x0 => pitch["x0"],
|
103
|
+
:y0 => pitch["y0"],
|
104
|
+
:z0 => pitch["z0"],
|
105
|
+
:vx0 => pitch["vx0"],
|
106
|
+
:vy0 => pitch["vy0"],
|
107
|
+
:vz0 => pitch["vz0"],
|
108
|
+
:ax => pitch["ax"],
|
109
|
+
:ay => pitch["ay"],
|
110
|
+
:az => pitch["az"],
|
111
|
+
:break_y => pitch["break_y"],
|
112
|
+
:break_angle => pitch["break_angle"],
|
113
|
+
:break_length => pitch["break_length"],
|
114
|
+
:pitch_type => pitch["pitch_type"],
|
115
|
+
:type_confidence => pitch["type_confidence"],
|
116
|
+
:zone => pitch["zone"],
|
117
|
+
:nasty => pitch["nasty"],
|
118
|
+
:spin_dir => pitch["spin_dir"],
|
119
|
+
:spin_rate => pitch["spin_rate"],
|
120
|
+
:cc => pitch["cc"],
|
121
|
+
:mt => pitch["mt"]})
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
last_pitch = doc.xpath("//game/inning/*/*/pitch/@id").map(&:value).map(&:to_i).max
|
127
|
+
|
128
|
+
sleep delay
|
129
|
+
|
130
|
+
if doc.xpath("//game").first["ind"] != "F"
|
131
|
+
doc = Nokogiri::HTML(open "#{@base_url}/inning/inning_all.xml")
|
132
|
+
end
|
133
|
+
end while game_status != "F"
|
134
|
+
end.each(&block)
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.base_url_for_date(date = Time.now.to_date)
|
138
|
+
"#{MLB_BASE_URL}/year_#{date.year}/month_#{"%02d" % date.month}/day_#{"%02d" % date.day}"
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
|
143
|
+
def player_lookup
|
144
|
+
doc = Nokogiri::HTML(open( "#{@base_url}/players.xml"))
|
145
|
+
Hash[doc.xpath("//game/team/player").map{|x| [x["id"], "#{x["first"]} #{x["last"]}"]}]
|
146
|
+
end
|
147
|
+
|
148
|
+
def game_status
|
149
|
+
doc = Nokogiri::HTML(open( "#{@base_url}/linescore.xml"))
|
150
|
+
doc.xpath("//game").first["ind"]
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
data/lib/mlb_terminal/version.rb
CHANGED
data/mlb_terminal.gemspec
CHANGED
@@ -9,8 +9,8 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.authors = ["Stefan Novak"]
|
10
10
|
s.email = ["stefan.louis.novak@gmail.com"]
|
11
11
|
s.homepage = "https://github.com/slnovak/mlb_terminal"
|
12
|
-
s.description = %q{A small terminal app to
|
13
|
-
s.summary = %q{
|
12
|
+
s.description = %q{A small terminal app to pipe formatted MLB baseball feeds into the terminal for easy manipulation. Includes access to both historic and real-time baseball feeds including play-by-play and pitch-by-pitch data. Visit the homepage for examples!}
|
13
|
+
s.summary = %q{A small terminal app for accessing historic and realtime MLB game data}
|
14
14
|
|
15
15
|
s.files = `git ls-files`.split("\n")
|
16
16
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mlb_terminal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -59,8 +59,9 @@ dependencies:
|
|
59
59
|
- - ~>
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: 3.2.8
|
62
|
-
description: A small terminal app to
|
63
|
-
for easy manipulation.
|
62
|
+
description: A small terminal app to pipe formatted MLB baseball feeds into the terminal
|
63
|
+
for easy manipulation. Includes access to both historic and real-time baseball feeds
|
64
|
+
including play-by-play and pitch-by-pitch data. Visit the homepage for examples!
|
64
65
|
email:
|
65
66
|
- stefan.louis.novak@gmail.com
|
66
67
|
executables:
|
@@ -75,7 +76,7 @@ files:
|
|
75
76
|
- Rakefile
|
76
77
|
- bin/mlb
|
77
78
|
- lib/mlb_terminal.rb
|
78
|
-
- lib/mlb_terminal/
|
79
|
+
- lib/mlb_terminal/game.rb
|
79
80
|
- lib/mlb_terminal/version.rb
|
80
81
|
- mlb_terminal.gemspec
|
81
82
|
homepage: https://github.com/slnovak/mlb_terminal
|
@@ -101,5 +102,5 @@ rubyforge_project:
|
|
101
102
|
rubygems_version: 1.8.24
|
102
103
|
signing_key:
|
103
104
|
specification_version: 3
|
104
|
-
summary:
|
105
|
+
summary: A small terminal app for accessing historic and realtime MLB game data
|
105
106
|
test_files: []
|
data/lib/mlb_terminal/client.rb
DELETED
@@ -1,85 +0,0 @@
|
|
1
|
-
require 'date'
|
2
|
-
require 'nokogiri'
|
3
|
-
require 'open-uri'
|
4
|
-
require 'active_support/core_ext/integer/inflections'
|
5
|
-
|
6
|
-
module MLBTerminal
|
7
|
-
MLB_BASE_URL = 'http://gd2.mlb.com/components/game/mlb'
|
8
|
-
|
9
|
-
class Client
|
10
|
-
def self.list_games(date = Time.now.to_date)
|
11
|
-
doc = Nokogiri::HTML(open "#{base_url_for_date date}/epg.xml")
|
12
|
-
doc.xpath("//epg/game").map{|game|
|
13
|
-
{:home_team => {
|
14
|
-
:name => game["home_team_name"],
|
15
|
-
:wins => game["home_win"],
|
16
|
-
:losses => game["home_loss"]},
|
17
|
-
:away_team => {
|
18
|
-
:name => game["away_team_name"],
|
19
|
-
:wins => game["away_win"],
|
20
|
-
:losses => game["away_loss"]},
|
21
|
-
:score => {
|
22
|
-
:home => game["home_team_runs"],
|
23
|
-
:away => game["away_team_runs"]},
|
24
|
-
:starts => "#{game["time"]} #{game["time_zone"]}",
|
25
|
-
:status => "#{game["status"]}" \
|
26
|
-
"#{game["status"] == "In Progress" ?
|
27
|
-
", #{game["top_inning"]=="Y" ? "Top" : "Bot"} of #{game["inning"].to_i.ordinalize}" :
|
28
|
-
""}",
|
29
|
-
:game_id => game["gameday"]}}
|
30
|
-
end
|
31
|
-
|
32
|
-
def initialize(gameday)
|
33
|
-
@gameday = gameday
|
34
|
-
year, month, day, game_name = /([0-9]{4})_([0-9]{2})_([0-9]{2})_(.*)/.match(@gameday).to_a.slice(1,4)
|
35
|
-
@base_url = "#{Client.base_url_for_date(Date.new(year.to_i, month.to_i, day.to_i))}/gid_#{@gameday}"
|
36
|
-
end
|
37
|
-
|
38
|
-
def events(start_inning = 1, end_inning = 9, delay = 5, &block)
|
39
|
-
current_inning = start_inning
|
40
|
-
current_inning_loc= "top"
|
41
|
-
|
42
|
-
innings = ["top", "bottom"]
|
43
|
-
|
44
|
-
Enumerator.new do |y|
|
45
|
-
while current_inning <= end_inning and not current_inning_loc.nil?
|
46
|
-
doc = Nokogiri::HTML(open "#{@base_url}/game_events.xml")
|
47
|
-
|
48
|
-
doc.xpath("//game/inning[@num >= #{current_inning}]").each do |inning|
|
49
|
-
|
50
|
-
current_inning_loc ||= "top"
|
51
|
-
|
52
|
-
innings.slice(innings.index(current_inning_loc), 2).each do |inning_loc|
|
53
|
-
if inning.xpath(inning_loc).nil?
|
54
|
-
break
|
55
|
-
else
|
56
|
-
inning.xpath("#{inning_loc}/atbat").each do |atbat|
|
57
|
-
y.yield({:inning => current_inning,
|
58
|
-
:num => atbat["num"],
|
59
|
-
:balls => atbat["b"],
|
60
|
-
:strikes => atbat["s"],
|
61
|
-
:outs => atbat["o"],
|
62
|
-
:time => Time.parse(atbat["start_tfs_zulu"], "%Y-%m-%dT%H:%M:%SZ"),
|
63
|
-
:desc => atbat["des"]})
|
64
|
-
end
|
65
|
-
|
66
|
-
current_inning_loc = innings[innings.index(current_inning_loc) + 1]
|
67
|
-
end
|
68
|
-
end
|
69
|
-
current_inning += 1
|
70
|
-
end
|
71
|
-
|
72
|
-
# If we had to break early, wait before trying again.
|
73
|
-
if current_inning != end_inning and not current_inning_loc.nil?
|
74
|
-
sleep delay
|
75
|
-
end
|
76
|
-
|
77
|
-
end
|
78
|
-
end.each(&block)
|
79
|
-
end
|
80
|
-
|
81
|
-
def self.base_url_for_date(date = Time.now.to_date)
|
82
|
-
"#{MLB_BASE_URL}/year_#{date.year}/month_#{"%02d" % date.month}/day_#{"%02d" % date.day}"
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|