├── .gitignore ├── Gemfile ├── lib ├── mlb_gameday │ ├── version.rb │ ├── batter.rb │ ├── division.rb │ ├── league.rb │ ├── player.rb │ ├── pitcher.rb │ ├── team.rb │ └── game.rb └── mlb_gameday.rb ├── Rakefile ├── .rubocop.yml ├── test ├── year_2014 │ ├── pitchers │ │ └── 477132.xml │ ├── month_05 │ │ └── day_28 │ │ │ └── gid_2014_05_28_cinmlb_lanmlb_1 │ │ │ ├── pitchers │ │ │ ├── 607162.xml │ │ │ ├── 543493.xml │ │ │ ├── 455092.xml │ │ │ ├── 502009.xml │ │ │ ├── 451532.xml │ │ │ ├── 457707.xml │ │ │ ├── 434442.xml │ │ │ ├── 459967.xml │ │ │ ├── 519437.xml │ │ │ ├── 547973.xml │ │ │ ├── 446185.xml │ │ │ ├── 448159.xml │ │ │ ├── 434181.xml │ │ │ ├── 445156.xml │ │ │ ├── 453198.xml │ │ │ ├── 455009.xml │ │ │ ├── 543331.xml │ │ │ ├── 124604.xml │ │ │ ├── 445276.xml │ │ │ ├── 477132.xml │ │ │ ├── 547943.xml │ │ │ ├── 571561.xml │ │ │ ├── 430904.xml │ │ │ ├── 451216.xml │ │ │ ├── 502190.xml │ │ │ ├── 277417.xml │ │ │ ├── 429717.xml │ │ │ ├── 430580.xml │ │ │ ├── 425844.xml │ │ │ ├── 456501.xml │ │ │ └── 456701.xml │ │ │ ├── batters │ │ │ ├── 445276.xml │ │ │ ├── 453198.xml │ │ │ ├── 455092.xml │ │ │ ├── 519437.xml │ │ │ ├── 607162.xml │ │ │ ├── 429717.xml │ │ │ ├── 430904.xml │ │ │ ├── 457707.xml │ │ │ ├── 459967.xml │ │ │ ├── 543331.xml │ │ │ ├── 547943.xml │ │ │ ├── 124604.xml │ │ │ ├── 425844.xml │ │ │ ├── 445156.xml │ │ │ ├── 446185.xml │ │ │ ├── 451532.xml │ │ │ ├── 502009.xml │ │ │ ├── 543493.xml │ │ │ ├── 571561.xml │ │ │ ├── 277417.xml │ │ │ ├── 430580.xml │ │ │ ├── 543148.xml │ │ │ ├── 544371.xml │ │ │ ├── 628326.xml │ │ │ ├── 434442.xml │ │ │ ├── 435219.xml │ │ │ ├── 451216.xml │ │ │ ├── 454560.xml │ │ │ ├── 456501.xml │ │ │ ├── 502190.xml │ │ │ ├── 408210.xml │ │ │ ├── 421124.xml │ │ │ ├── 448159.xml │ │ │ ├── 455009.xml │ │ │ ├── 547973.xml │ │ │ ├── 475100.xml │ │ │ ├── 502317.xml │ │ │ ├── 346874.xml │ │ │ ├── 408307.xml │ │ │ ├── 434181.xml │ │ │ ├── 458015.xml │ │ │ ├── 457449.xml │ │ │ ├── 477132.xml │ │ │ ├── 465668.xml │ │ │ ├── 456701.xml │ │ │ ├── 435401.xml │ │ │ ├── 460077.xml │ │ │ ├── 457759.xml │ │ │ ├── 519023.xml │ │ │ ├── 571740.xml │ │ │ ├── 430910.xml │ │ │ ├── 434670.xml │ │ │ ├── 446359.xml │ │ │ ├── 543829.xml │ │ │ ├── 461314.xml │ │ │ ├── 407886.xml │ │ │ ├── 457803.xml │ │ │ ├── 444843.xml │ │ │ ├── 453943.xml │ │ │ ├── 408236.xml │ │ │ ├── 624577.xml │ │ │ └── 408252.xml │ │ │ ├── linescore.xml │ │ │ └── gamecenter.xml │ └── month_07 │ │ └── day_15 │ │ └── gid_2014_07_15_nasmlb_aasmlb_1 │ │ └── pitchers │ │ └── 477132.xml ├── download.rb ├── game_spec.rb └── api_spec.rb ├── CHANGELOG.md ├── README.md ├── LICENSE.txt ├── mlb_gameday.gemspec └── resources └── data.yml /.gitignore: -------------------------------------------------------------------------------- 1 | Gemfile.lock 2 | pkg 3 | test/year_2014 4 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | gemspec 6 | -------------------------------------------------------------------------------- /lib/mlb_gameday/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module MLBGameday 4 | VERSION = '0.3.2' 5 | end 6 | -------------------------------------------------------------------------------- /lib/mlb_gameday/batter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module MLBGameday 4 | class Batter < Player 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'bundler/gem_tasks' 4 | require 'rake/testtask' 5 | require 'rspec/core/rake_task' 6 | 7 | Rake::TestTask.new do |t| 8 | t.pattern = 'test/*_spec.rb' 9 | end 10 | 11 | task default: :test 12 | -------------------------------------------------------------------------------- /lib/mlb_gameday/division.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module MLBGameday 4 | class Division 5 | attr_reader :id, :league, :name, :teams 6 | 7 | def initialize(id:, league:, name:, teams:) 8 | @id = id 9 | @league = league 10 | @name = name 11 | @teams = teams 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/mlb_gameday/league.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module MLBGameday 4 | class League 5 | attr_reader :name, :divisions 6 | 7 | def initialize(name, divisions) 8 | @name = name 9 | @divisions = divisions 10 | end 11 | 12 | def division(name) 13 | raise 'Invalid division' unless %i[East Central West].include?(name) 14 | 15 | @divisions[name] 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | Include: 3 | - Rakefile 4 | - Gemfile 5 | TargetRubyVersion: 2.5 6 | 7 | Layout/MultilineMethodCallIndentation: 8 | EnforcedStyle: indented 9 | 10 | Metrics/AbcSize: 11 | Enabled: false 12 | 13 | Metrics/ClassLength: 14 | Max: 100 15 | 16 | Metrics/CyclomaticComplexity: 17 | Enabled: false 18 | 19 | Metrics/MethodLength: 20 | Max: 15 21 | 22 | Style/Documentation: 23 | Enabled: false 24 | -------------------------------------------------------------------------------- /test/year_2014/pitchers/477132.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/mlb_gameday/player.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module MLBGameday 4 | class Player 5 | attr_reader :id, :data 6 | 7 | def initialize(id:, xml:) 8 | @id = id 9 | @data = xml 10 | end 11 | 12 | def first_name 13 | @data.xpath('//Player//@first_name').text 14 | end 15 | 16 | def last_name 17 | @data.xpath('//Player//@last_name').text 18 | end 19 | 20 | def name 21 | "#{first_name} #{last_name}" 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 0.3.2 4 | 5 | * Don't load an extra XML file at the end of the game to find the W/L/S pitcher's stats. 6 | 7 | ## 0.3.1 8 | 9 | * Changed back to gdx - the redirect is gone. 10 | 11 | ## 0.3.0 12 | 13 | * Changed data source to gd-terr-origin.mlb.com since gdx.mlb.com redirects there. 14 | * Code cleanup. 15 | 16 | ## 0.2.3 / 0.2.4 17 | 18 | * Add All Star teams 19 | 20 | ## 0.2.1 / 0.2.2 21 | 22 | * Recognize "d-backs" as a name for the Diamondbacks 23 | 24 | ## 0.2.0 25 | 26 | * Added game attendance, weather, wind, elapsed time, and umpires 27 | * Understand a few more game statuses 28 | * Use Ruby 2.4 lonely operator (&.) **This drops compatibility for Ruby 2.3 and below.** 29 | * Fixed implicit names bug (thanks to @cacqw7) [#4](https://github.com/Fustrate/mlb_gameday/pull/4) 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The Gameday API has been deprecated by MLB 2 | 3 | This gem is no longer under development. Use [the MLB Stats API gem](//github.com/Fustrate/mlb_stats_api) instead. 4 | 5 | # MLBGameday 6 | 7 | TODO: Write a gem description 8 | 9 | ## Installation 10 | 11 | Add this line to your application's Gemfile: 12 | 13 | gem 'mlb_gameday' 14 | 15 | And then execute: 16 | 17 | $ bundle 18 | 19 | Or install it yourself as: 20 | 21 | $ gem install mlb_gameday 22 | 23 | ## Usage 24 | 25 | `require 'mlb_gameday' #=> true` 26 | `gd2 = MLBGameday::API.new` 27 | 28 | ## Contributing 29 | 30 | 1. Fork it 31 | 2. Create your feature branch (`git checkout -b my-new-feature`) 32 | 3. Commit your changes (`git commit -am 'Add some feature'`) 33 | 4. Push to the branch (`git push origin my-new-feature`) 34 | 5. Create new Pull Request 35 | -------------------------------------------------------------------------------- /lib/mlb_gameday/pitcher.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module MLBGameday 4 | class Pitcher < Player 5 | def era 6 | @data.xpath('//Player/season/@era').text.to_f 7 | end 8 | 9 | def wins 10 | @data.xpath('//Player/season/@w').text.to_i 11 | end 12 | 13 | def losses 14 | @data.xpath('//Player/season/@l').text.to_i 15 | end 16 | 17 | def innings 18 | @data.xpath('//Player/season/@ip').text.to_f 19 | end 20 | 21 | def saves 22 | @data.xpath('//Player/season/@sv').text.to_i 23 | end 24 | 25 | def whip 26 | @data.xpath('//Player/season/@whip').text.to_f 27 | end 28 | 29 | def strikeouts 30 | @data.xpath('//Player/season/@so').text.to_i 31 | end 32 | 33 | def walks 34 | @data.xpath('//Player/season/@bb').text.to_i 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /test/download.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'open-uri' 4 | require 'fileutils' 5 | 6 | raise 'Please pass a URL to this program.' if ARGV[0].empty? 7 | 8 | def download_url(url) 9 | response = open(url) 10 | 11 | puts "Downloading #{url}" 12 | 13 | raise "Error downloading #{url}" unless response.status[0] == '200' 14 | 15 | handle_file url, response.read 16 | end 17 | 18 | def handle_file(url, body) 19 | filename = url.gsub 'http://gd2.mlb.com/components/game/mlb/', '' 20 | 21 | if body['Index of'] 22 | body.scan(%r{
  • \s*(.*)
  • }) do |match| 23 | # Only the "Parent Directory" link is different 24 | next if match[0] != match[1] 25 | 26 | download_url("#{url}/#{match[0]}") 27 | end 28 | else 29 | # Save the file 30 | save_file filename, body 31 | end 32 | end 33 | 34 | def save_file(filename, body) 35 | save_path = File.join Dir.pwd, filename 36 | FileUtils.mkdir_p File.dirname save_path 37 | File.open(save_path, 'w') { |file| file.write body } 38 | end 39 | 40 | download_url ARGV[0] 41 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Steven Hoffman 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /mlb_gameday.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | lib = File.expand_path('../lib', __FILE__) 4 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 5 | require 'mlb_gameday/version' 6 | 7 | Gem::Specification.new do |spec| 8 | spec.name = 'mlb_gameday' 9 | spec.version = MLBGameday::VERSION 10 | spec.authors = ['Steven Hoffman'] 11 | spec.email = ['git@fustrate.com'] 12 | spec.description = 'Access data about games and players from the ' \ 13 | 'official MLB Gameday API' 14 | spec.summary = 'Fetches gameday data from the MLB Gameday API' 15 | spec.homepage = 'http://github.com/fustrate/mlb_gameday' 16 | spec.license = 'MIT' 17 | 18 | spec.files = `git ls-files`.split($RS) 19 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 20 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 21 | spec.require_paths = %w[lib] 22 | 23 | spec.add_development_dependency 'bundler', '~> 1.9' 24 | spec.add_development_dependency 'minitest', '~> 5.5' 25 | spec.add_development_dependency 'rake', '~> 10.4' 26 | 27 | spec.add_dependency 'chronic', '~> 0.10' 28 | spec.add_dependency 'httparty', '~> 0.13' 29 | spec.add_dependency 'nokogiri', '~> 1.6' 30 | end 31 | -------------------------------------------------------------------------------- /lib/mlb_gameday/team.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module MLBGameday 4 | class Team 5 | attr_reader :id, :name, :city, :league, :division, :code, :file_code 6 | 7 | def initialize(opts = {}) 8 | @id = opts[:id] 9 | @name = opts[:name] 10 | @city = opts[:city] 11 | @league = opts[:league] 12 | @division = opts[:division] 13 | @alt_names = opts[:alt_names] 14 | @code = opts[:code] 15 | @file_code = opts[:file_code] 16 | end 17 | 18 | def full_name 19 | "#{city} #{name}" 20 | end 21 | 22 | def names 23 | @names ||= (implicit_names + alt_names).uniq 24 | end 25 | 26 | def called?(name) 27 | names.include?(name.downcase) 28 | end 29 | 30 | # So we don't get huge printouts 31 | def inspect 32 | %(#) 33 | end 34 | 35 | private 36 | 37 | def alt_names 38 | @alt_names ||= [] 39 | end 40 | 41 | def implicit_names 42 | result = strict_names 43 | result << [code, singular_name, despaced_name].map(&:downcase) 44 | result << city.downcase unless ['New York', 'Chicago'].include?(city) 45 | 46 | result.flatten.uniq 47 | end 48 | 49 | def strict_names 50 | [name, full_name].map(&:downcase) 51 | end 52 | 53 | def singular_name 54 | name.chomp 's' 55 | end 56 | 57 | def despaced_name 58 | name.tr ' ', '' 59 | end 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/607162.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/543493.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/455092.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/502009.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/451532.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/445276.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/453198.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/455092.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/519437.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/607162.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/429717.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/430904.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/457707.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/459967.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/543331.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/547943.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/124604.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/425844.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/445156.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/446185.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/451532.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/502009.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/543493.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/571561.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/457707.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/277417.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/430580.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/543148.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/544371.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/628326.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/434442.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/435219.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/451216.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/454560.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/456501.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/502190.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/408210.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/421124.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/448159.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/455009.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/547973.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/434442.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/459967.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/519437.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/547973.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/475100.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/446185.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/448159.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/434181.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/445156.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/453198.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/455009.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/543331.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/502317.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/124604.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/445276.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/346874.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/408307.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/477132.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/547943.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/571561.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_07/day_15/gid_2014_07_15_nasmlb_aasmlb_1/pitchers/477132.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/434181.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/458015.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/430904.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/451216.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/502190.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/277417.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/429717.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/430580.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/457449.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/425844.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/456501.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/pitchers/456701.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/477132.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/465668.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/456701.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/435401.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/460077.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/457759.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/519023.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/571740.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/430910.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/434670.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/446359.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/543829.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/461314.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/407886.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/457803.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/444843.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/453943.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/408236.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/624577.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/batters/408252.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/game_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'minitest/autorun' 4 | require 'mlb_gameday.rb' 5 | 6 | # Mock the basic `open` function so we don't actually hit the MLB website 7 | class MockedApi < MLBGameday::API 8 | alias old_open open 9 | 10 | def open(url, &block) 11 | dir = File.dirname __FILE__ 12 | base = url.gsub 'http://gdx.mlb.com/components/game/mlb/', '' 13 | path = File.join dir, base 14 | 15 | unless File.exist?(path) 16 | puts "Downloading from website: #{url}" 17 | 18 | return old_open(url, &block) 19 | end 20 | 21 | file = File.open path 22 | 23 | return file unless block_given? 24 | 25 | yield file 26 | end 27 | end 28 | 29 | class TestGame < MiniTest::Test 30 | def setup 31 | @api = MockedApi.new 32 | @game = @api.game('2014_05_28_cinmlb_lanmlb_1') 33 | # @free_game = @api.game('2013_04_01_slnmlb_arimlb_1') 34 | end 35 | 36 | def test_load_game_from_gid 37 | assert_equal 'Dodgers', @game.home_team.name 38 | end 39 | 40 | def test_load_game_for_team_on_date 41 | dodgers = @api.team('Dodgers') 42 | 43 | games = @api.find_games(team: dodgers, date: Date.parse('2014-05-28')) 44 | 45 | assert_equal 1, games.count 46 | end 47 | 48 | def test_game_has_two_teams 49 | assert_equal 2, @game.teams.count 50 | end 51 | 52 | def test_correct_venue 53 | assert_equal 'Dodger Stadium', @game.venue 54 | end 55 | 56 | def test_home_start_time 57 | assert_equal '7:10 PM PT', @game.home_start_time 58 | end 59 | 60 | def test_away_start_time 61 | assert_equal '10:10 PM ET', @game.away_start_time 62 | end 63 | 64 | def test_home_starting_pitcher 65 | assert_equal 'Clayton Kershaw', @game.home_pitcher.name 66 | end 67 | 68 | def test_home_tv 69 | assert_equal 'SportsNet LA, SNLA Spanish', @game.home_tv 70 | end 71 | 72 | def test_away_radio 73 | assert_equal 'WLW 700, Reds Radio Network', @game.away_radio 74 | end 75 | 76 | def test_free_game_1 77 | refute @game.free? 78 | end 79 | 80 | def test_free_game_2 81 | skip 'Free game not yet loaded.' 82 | 83 | assert @free_game.free? 84 | end 85 | 86 | def test_game_attendance 87 | assert_equal '41,129', @game.attendance 88 | end 89 | 90 | def test_game_elapsed_time 91 | assert_equal '3:08', @game.elapsed_time 92 | end 93 | 94 | def test_game_weather 95 | assert_equal '71 degrees, partly cloudy', @game.weather 96 | end 97 | 98 | def test_game_wind 99 | assert_equal '8 mph, Out to CF', @game.wind 100 | end 101 | 102 | def test_game_umpires 103 | assert_equal( 104 | { 105 | 'HP' => 'Phil Cuzzi', 106 | '1B' => 'Gerry Davis', 107 | '2B' => 'Quinn Wolcott', 108 | '3B' => 'Greg Gibson' 109 | }, 110 | @game.umpires 111 | ) 112 | end 113 | end 114 | -------------------------------------------------------------------------------- /test/api_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'minitest/autorun' 4 | require 'mlb_gameday.rb' 5 | 6 | class TestApi < MiniTest::Test 7 | def setup 8 | @api = MLBGameday::API.new 9 | end 10 | 11 | def test_api_created 12 | refute_nil @api 13 | end 14 | 15 | def test_league_count 16 | assert_equal 2, @api.leagues.count 17 | end 18 | 19 | def test_division_count 20 | assert_equal 6, @api.divisions.count 21 | end 22 | 23 | def test_team_count 24 | assert_equal 32, @api.teams.count 25 | end 26 | 27 | def test_initial_search 28 | assert_equal 'Los Angeles', @api.team('LAD').city 29 | end 30 | 31 | def test_name_search 32 | assert_equal 'Los Angeles', @api.team('Dodgers').city 33 | end 34 | 35 | def test_name_search_for_nonexistent_returns_nil 36 | assert_nil @api.team('Senators') 37 | end 38 | 39 | def test_division_team_count 40 | assert_equal 5, @api.team('Dodgers').division.teams.count 41 | end 42 | 43 | def test_astros_in_al_west 44 | assert_equal 'American', @api.team('Astros').league.name 45 | assert_equal 'West', @api.team('Astros').division.name 46 | end 47 | 48 | def test_names_includes_code 49 | @api.teams.each do |team| 50 | assert_includes team.names, team.code.downcase 51 | end 52 | end 53 | 54 | def test_names_includes_name 55 | @api.teams.each do |team| 56 | assert_includes team.names, team.name.downcase 57 | end 58 | end 59 | 60 | def test_names_includes_alt_names 61 | @api.teams.each do |team| 62 | team.send(:alt_names).each do |alt_name| 63 | assert_includes team.names, alt_name.downcase 64 | end 65 | end 66 | end 67 | 68 | def test_names_include_singular_name_when_different_from_name 69 | @api.teams 70 | .reject { |team| team.name == team.send(:singular_name) } 71 | .each do |team| 72 | assert_includes team.names, team.send(:singular_name).downcase 73 | end 74 | end 75 | 76 | def test_names_includes_despaced_name_when_name_is_multi_word 77 | @api.teams 78 | .select { |team| team.name.split.size > 1 } 79 | .each do |team| 80 | assert_includes team.names, team.send(:despaced_name).downcase 81 | end 82 | end 83 | 84 | def test_names_includes_city_except_nyc_and_chicago 85 | @api.teams 86 | .reject { |team| ['New York', 'Chicago'].include?(team.city) } 87 | .each do |team| 88 | assert_includes team.names, team.city.downcase 89 | end 90 | end 91 | 92 | def test_names_does_not_include_city_for_nyc_and_chicago 93 | @api.teams 94 | .select { |team| ['New York', 'Chicago'].include?(team.city) } 95 | .each do |team| 96 | refute_includes team.names, team.city.downcase 97 | end 98 | end 99 | 100 | def test_no_teams_share_any_names 101 | @api.teams.each do |team| 102 | @api.teams.reject { |t| t == team }.each do |other_team| 103 | assert_equal (team.names - other_team.names), team.names 104 | end 105 | end 106 | end 107 | 108 | def test_all_star_teams 109 | assert_equal 2, @api.teams.select { |t| t.name['All Stars'] }.length 110 | end 111 | end 112 | -------------------------------------------------------------------------------- /lib/mlb_gameday.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'httparty' 4 | require 'nokogiri' 5 | require 'open-uri' 6 | require 'psych' 7 | require 'chronic' 8 | 9 | %w[version league division team game player pitcher batter].each do |file| 10 | require "mlb_gameday/#{file}" 11 | end 12 | 13 | module MLBGameday 14 | API_URL = 'http://gdx.mlb.com/components/game/mlb' 15 | 16 | BATTER = '/year_%d/batters/%d' 17 | PITCHER = '/year_%d/pitchers/%d' 18 | GAME_FOLDER = '/year_%d/month_%02d/day_%02d/gid_%s' 19 | SCOREBOARD = '/year_%Y/month_%m/day_%d/miniscoreboard' 20 | 21 | class API 22 | attr_reader :leagues 23 | 24 | def initialize 25 | @data = Psych.load File.open File.join( 26 | File.dirname(File.expand_path(__FILE__)), '../resources/data.yml' 27 | ) 28 | 29 | @leagues = @data[:leagues] 30 | end 31 | 32 | def league(name) 33 | return name if name.is_a? MLBGameday::League 34 | 35 | @leagues[name] 36 | end 37 | 38 | def team(name) 39 | return name if name.is_a? MLBGameday::Team 40 | 41 | teams.find { |team| team.called?(name) } 42 | end 43 | 44 | def teams 45 | @teams ||= divisions.map(&:teams).map(&:values).flatten + 46 | miscellaneous_teams 47 | end 48 | 49 | def miscellaneous_teams 50 | @data[:miscellaneous_teams].values 51 | end 52 | 53 | def division(league, name) 54 | @leagues[league][name] 55 | end 56 | 57 | def divisions 58 | @divisions ||= @leagues[:AL].divisions.values + 59 | @leagues[:NL].divisions.values 60 | end 61 | 62 | def pitcher(id, year: nil, gid: nil) 63 | return if id.empty? 64 | 65 | MLBGameday::Pitcher.new id: id, xml: pitcher_xml(id, year: year, gid: gid) 66 | end 67 | 68 | def batter(id, year: nil, gid: nil) 69 | return if id.empty? 70 | 71 | MLBGameday::Batter.new id: id, xml: batter_xml(id, year: year, gid: gid) 72 | end 73 | 74 | def game(gid) 75 | MLBGameday::Game.new( 76 | self, 77 | gid, 78 | gamecenter: gamecenter_xml(gid), 79 | linescore: linescore_xml(gid), 80 | rawboxscore: rawboxscore_xml(gid) 81 | ) 82 | end 83 | 84 | def find_games(team: nil, date: nil) 85 | doc = scoreboard_xml(date || Date.today) 86 | 87 | if team 88 | code = team(team).code 89 | 90 | doc.xpath('//games/game').map do |game| 91 | next unless [game.xpath('@home_name_abbrev').text, 92 | game.xpath('@away_name_abbrev').text].include? code 93 | 94 | game game.xpath('@gameday_link').text 95 | end.compact! 96 | else 97 | doc.xpath('//games/game').map do |game| 98 | game game.xpath('@gameday_link').to_s 99 | end 100 | end 101 | end 102 | 103 | def scoreboard_xml(date) 104 | fetch_xml date.strftime SCOREBOARD 105 | end 106 | 107 | def linescore_xml(gid) 108 | fetch_xml "#{GAME_FOLDER}/linescore", gid: gid 109 | end 110 | 111 | def rawboxscore_xml(gid) 112 | fetch_xml "#{GAME_FOLDER}/rawboxscore", gid: gid 113 | end 114 | 115 | def gamecenter_xml(gid) 116 | fetch_xml "#{GAME_FOLDER}/gamecenter", gid: gid 117 | end 118 | 119 | def batter_xml(id, year: nil, gid: nil) 120 | # We only really want one piece of data from this file. This gives us 121 | # the GID of their most recent appearance. 122 | gid ||= fetch_xml(BATTER, id: id, year: (year || Date.today.year)) 123 | .xpath('//batting/@game_id').text.gsub(/[^a-z0-9]/, '_') 124 | 125 | fetch_xml "#{GAME_FOLDER}/batters/%s", gid: gid, batter: id 126 | end 127 | 128 | def pitcher_xml(id, year: nil, gid: nil) 129 | # We only really want one piece of data from this file. This gives us 130 | # the GID of their most recent appearance. 131 | gid ||= fetch_xml(PITCHER, id: id, year: (year || Date.today.year)) 132 | .xpath('//pitching/@game_id').text.gsub(/[^a-z0-9]/, '_') 133 | 134 | fetch_xml "#{GAME_FOLDER}/pitchers/%s", gid: gid, pitcher: id 135 | end 136 | 137 | protected 138 | 139 | def fetch_xml(path, interpolations = {}) 140 | full_path = "#{API_URL}#{path}.xml" 141 | 142 | if interpolations[:gid] 143 | year, month, day, = interpolations[:gid].split '_' 144 | 145 | interpolations[:year] = year 146 | interpolations[:month] = month 147 | interpolations[:day] = day 148 | end 149 | 150 | full_path = format(full_path, interpolations) if interpolations.any? 151 | 152 | Nokogiri::XML open full_path 153 | rescue 154 | nil 155 | end 156 | end 157 | end 158 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/linescore.xml: -------------------------------------------------------------------------------- 1 | 2 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 103 | 112 | 122 | 123 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /test/year_2014/month_05/day_28/gid_2014_05_28_cinmlb_lanmlb_1/gamecenter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Dodger Stadium 4 | Dodger Stadium 5 | 6 | 7 | 8 | SportsNet LA, SNLA Spanish 9 | 570 Fox Sports L.A. , KTNQ 1020 10 | 11 | 12 | FS-O 13 | WLW 700, Reds Radio Network 14 | 15 | 16 | 17 | 18 | 19 | 477132 20 | Clayton 21 | Kershaw 22 | Kershaw 23 | 22 24 | LHP 25 | 3 26 | 1 27 | 3.49 28 | 37 29 | 3 30 | 1 31 | 3.49 32 | 37 33 | 34 | Kershaw's RBI groundout 35 | 36 | 37 | 38 | 39 | 40 | 456701 41 | Homer 42 | Bailey 43 | Bailey, H 44 | 34 45 | RHP 46 | 4 47 | 3 48 | 5.34 49 | 50 50 | 4 51 | 3 52 | 5.34 53 | 50 54 | 55 | Bailey on career-high 12 K's 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | http://mediadownloads.mlb.com/mlbam/2014/05/29/images/mlbf_33264035_th_7.jpg 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | /assets/images/1/1/0/77312110/cuts/Homer_Bailey_spzhqcru_xq76bdsx.jpg 92 | /assets/images/1/1/0/77312110/cuts/Homer_Bailey_spzhqcru_xq76bdsx@2x.jpg 93 | /assets/images/1/1/0/77312110/cuts/Homer_Bailey_spzhqcru_v5y2ik4u.jpg 94 | /assets/images/1/1/0/77312110/cuts/Homer_Bailey_spzhqcru_v5y2ik4u@2x.jpg 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | <![CDATA[Bailey's strong start]]> 104 | 00:02:10 105 | 106 | http://mediadownloads.mlb.com/mlbam/2014/05/29/mlbtv_cinlan_33264035_300K.mp4 107 | http://mediadownloads.mlb.com/mlbam/2014/05/29/mlbtv_cinlan_33264035_600K.mp4 108 | http://mediadownloads.mlb.com/mlbam/2014/05/29/mlbtv_cinlan_33264035_1200K.mp4 109 | http://mediadownloads.mlb.com/mlbam/2014/05/29/mlbtv_cinlan_33264035_1800K.mp4 110 | http://mediadownloads.mlb.com/mlbam/2014/05/29/33264035_m3u8/master_mobile.m3u8 111 | http://mediadownloads.mlb.com/mlbam/2014/05/29/33264035_m3u8/master_tablet.m3u8 112 | http://mediadownloads.mlb.com/mlbam/2014/05/29/33264035_m3u8/master_android_tablet.m3u8 113 | http://mediadownloads.mlb.com/mlbam/2014/05/29/images/mlbf_33264035_th_7.jpg 114 | 115 | -------------------------------------------------------------------------------- /lib/mlb_gameday/game.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module MLBGameday 4 | # This class is just too long. It might be able to be split up, but it's not 5 | # likely to happen any time soon. For now, we'll disable the cop. 6 | # rubocop:disable Metrics/ClassLength 7 | class Game 8 | attr_reader :gid, :home_team, :away_team, :files 9 | 10 | def initialize(api, gid, files = {}) 11 | @api = api 12 | @gid = gid 13 | @files = files 14 | 15 | @home_team = @api.team home_team_identifier 16 | @away_team = @api.team away_team_identifier 17 | end 18 | 19 | def teams 20 | [@home_team, @away_team] 21 | end 22 | 23 | def venue 24 | if @files[:linescore] 25 | return @files[:linescore].xpath('//game/@venue').text 26 | end 27 | 28 | files[:gamecenter].xpath('//game/venueShort').text 29 | end 30 | 31 | def home_start_time(ampm: true) 32 | if ampm 33 | [ 34 | @files[:linescore].xpath('//game/@home_time').text, 35 | @files[:linescore].xpath('//game/@home_ampm').text, 36 | @files[:linescore].xpath('//game/@home_time_zone').text 37 | ].join ' ' 38 | else 39 | [ 40 | @files[:linescore].xpath('//game/@home_time').text, 41 | @files[:linescore].xpath('//game/@home_time_zone').text 42 | ].join ' ' 43 | end 44 | end 45 | 46 | def away_start_time(ampm: true) 47 | if ampm 48 | [ 49 | @files[:linescore].xpath('//game/@away_time').text, 50 | @files[:linescore].xpath('//game/@away_ampm').text, 51 | @files[:linescore].xpath('//game/@away_time_zone').text 52 | ].join ' ' 53 | else 54 | [ 55 | @files[:linescore].xpath('//game/@away_time').text, 56 | @files[:linescore].xpath('//game/@away_time_zone').text 57 | ].join ' ' 58 | end 59 | end 60 | 61 | # Preview, Pre-Game, In Progress, Final 62 | def status 63 | return 'Preview' unless @files[:linescore] 64 | 65 | @status ||= @files[:linescore].xpath('//game/@status').text 66 | end 67 | 68 | # [3, Top/Middle/Bottom/End] 69 | def inning 70 | return [0, '?'] unless @files[:linescore]&.xpath('//game/@inning') 71 | 72 | [ 73 | @files[:linescore].xpath('//game/@inning').text.to_i, 74 | @files[:linescore].xpath('//game/@inning_state').text 75 | ] 76 | end 77 | 78 | def runners 79 | first = nil 80 | second = nil 81 | third = nil 82 | 83 | [first, second, third] 84 | end 85 | 86 | def over? 87 | ['Final', 'Game Over', 'Completed Early'].include? status 88 | end 89 | alias fat_lady_has_sung? over? 90 | 91 | def in_progress? 92 | status == 'In Progress' 93 | end 94 | 95 | def started? 96 | over? || in_progress? 97 | end 98 | 99 | def postponed? 100 | status == 'Postponed' 101 | end 102 | 103 | def home_record 104 | return [0, 0] unless @files[:linescore] 105 | 106 | [ 107 | @files[:linescore].xpath('//game/@home_win'), 108 | @files[:linescore].xpath('//game/@home_loss') 109 | ].map(&:text).map(&:to_i) 110 | end 111 | 112 | def away_record 113 | return [0, 0] unless @files[:linescore] 114 | 115 | [ 116 | @files[:linescore].xpath('//game/@away_win'), 117 | @files[:linescore].xpath('//game/@away_loss') 118 | ].map(&:text).map(&:to_i) 119 | end 120 | 121 | def current_pitcher 122 | return nil unless in_progress? 123 | 124 | @api.pitcher @files[:linescore].xpath('//game/current_pitcher/@id').text, 125 | year: date.year 126 | end 127 | 128 | def opposing_pitcher 129 | return nil unless in_progress? 130 | 131 | @api.pitcher @files[:linescore].xpath('//game/opposing_pitcher/@id').text, 132 | year: date.year 133 | end 134 | 135 | def winning_pitcher 136 | return nil unless over? 137 | 138 | @api.pitcher @files[:linescore].xpath('//game/winning_pitcher/@id').text, 139 | year: date.year, 140 | gid: @gid 141 | end 142 | 143 | def losing_pitcher 144 | return nil unless over? 145 | 146 | @api.pitcher @files[:linescore].xpath('//game/losing_pitcher/@id').text, 147 | year: date.year, 148 | gid: @gid 149 | end 150 | 151 | def save_pitcher 152 | return nil unless over? 153 | 154 | @api.pitcher @files[:linescore].xpath('//game/save_pitcher/@id').text, 155 | year: date.year, 156 | gid: @gid 157 | end 158 | 159 | def away_starting_pitcher 160 | return '' unless @files[:linescore] 161 | 162 | @files[:linescore].xpath('//game/away_probable_pitcher/@id').text 163 | end 164 | 165 | def home_starting_pitcher 166 | return '' unless @files[:linescore] 167 | 168 | @files[:linescore].xpath('//game/home_probable_pitcher/@id').text 169 | end 170 | 171 | def score 172 | return [0, 0] unless in_progress? || over? 173 | 174 | [ 175 | @files[:linescore].xpath('//game/@home_team_runs').text, 176 | @files[:linescore].xpath('//game/@away_team_runs').text 177 | ].map(&:to_i) 178 | end 179 | 180 | def home_pitcher 181 | # Spring training games can end in ties, in which case there's 182 | # really no pitching data. This should really return a null object. 183 | case status 184 | when 'In Progress' 185 | # The xpath changes based on which half of the inning it is 186 | if @files[:linescore].xpath('//game/@top_inning').text == 'Y' 187 | opposing_pitcher 188 | else 189 | current_pitcher 190 | end 191 | when 'Preview', 'Warmup', 'Pre-Game' 192 | @api.pitcher home_starting_pitcher 193 | when 'Final' 194 | home, away = score 195 | 196 | home > away ? winning_pitcher : losing_pitcher 197 | end 198 | end 199 | 200 | def away_pitcher 201 | # Spring training games can end in ties, in which case there's 202 | # really no pitching data. This should really return a null object. 203 | case status 204 | when 'In Progress' 205 | # The xpath changes based on which half of the inning it is 206 | if @files[:linescore].xpath('//game/@top_inning').text == 'Y' 207 | current_pitcher 208 | else 209 | opposing_pitcher 210 | end 211 | when 'Preview', 'Warmup', 'Pre-Game' 212 | @api.pitcher away_starting_pitcher 213 | when 'Final', 'Game Over' 214 | home, away = score 215 | 216 | home > away ? losing_pitcher : winning_pitcher 217 | end 218 | end 219 | 220 | def home_tv 221 | return nil unless files[:gamecenter] 222 | 223 | files[:gamecenter].xpath('//game/broadcast/home/tv').text 224 | end 225 | 226 | def away_tv 227 | return nil unless files[:gamecenter] 228 | 229 | files[:gamecenter].xpath('//game/broadcast/away/tv').text 230 | end 231 | 232 | def home_radio 233 | return nil unless files[:gamecenter] 234 | 235 | files[:gamecenter].xpath('//game/broadcast/home/radio').text 236 | end 237 | 238 | def away_radio 239 | return nil unless files[:gamecenter] 240 | 241 | files[:gamecenter].xpath('//game/broadcast/away/radio').text 242 | end 243 | 244 | def free? 245 | return false unless @files[:linescore] 246 | 247 | @files[:linescore].xpath('//game/game_media/media/@free').text == 'ALL' 248 | end 249 | 250 | def date 251 | return Date.today unless @files[:linescore] # SUPER KLUDGE 252 | 253 | @date ||= Chronic.parse( 254 | @files[:linescore].xpath('//game/@original_date').text 255 | ) 256 | end 257 | 258 | def attendance 259 | @files[:rawboxscore]&.xpath('//boxscore/@attendance')&.text || '0' 260 | end 261 | 262 | def elapsed_time 263 | @files[:rawboxscore]&.xpath('//boxscore/@elapsed_time')&.text || '' 264 | end 265 | 266 | def weather 267 | @files[:rawboxscore]&.xpath('//boxscore/@weather')&.text || '' 268 | end 269 | 270 | def wind 271 | @files[:rawboxscore]&.xpath('//boxscore/@wind')&.text || '' 272 | end 273 | 274 | def umpires 275 | return [] unless @files[:rawboxscore] 276 | 277 | umps = {} 278 | 279 | @files[:rawboxscore].xpath('//boxscore/umpires/umpire').each do |umpire| 280 | umps[umpire.xpath('@position').text] = umpire.xpath('@name').text 281 | end 282 | 283 | umps 284 | end 285 | 286 | # So we don't get huge printouts 287 | def inspect 288 | %(#) 289 | end 290 | 291 | protected 292 | 293 | def home_team_identifier 294 | if files[:linescore] 295 | return files[:linescore].xpath('//game/@home_name_abbrev').text 296 | end 297 | 298 | files[:gamecenter].xpath('//game/@id').text[18, 6] 299 | end 300 | 301 | def away_team_identifier 302 | if files[:linescore] 303 | return files[:linescore].xpath('//game/@away_name_abbrev').text 304 | end 305 | 306 | files[:gamecenter].xpath('//game/@id').text[11, 6] 307 | end 308 | end 309 | # rubocop:enable Metrics/ClassLength 310 | end 311 | -------------------------------------------------------------------------------- /resources/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | :leagues: 3 | :AL: &al !ruby/object:MLBGameday::League 4 | name: American 5 | divisions: 6 | :East: &aleast !ruby/object:MLBGameday::Division 7 | name: East 8 | league: *al 9 | id: 201 10 | teams: 11 | :BAL: !ruby/object:MLBGameday::Team 12 | name: Orioles 13 | city: Baltimore 14 | league: *al 15 | division: *aleast 16 | code: BAL 17 | file_code: bal 18 | id: 110 19 | alt_names: [balmlb] 20 | :BOS: !ruby/object:MLBGameday::Team 21 | name: Red Sox 22 | city: Boston 23 | league: *al 24 | division: *aleast 25 | code: BOS 26 | file_code: bos 27 | id: 111 28 | alt_names: [bosox, bosmlb] 29 | :NYY: !ruby/object:MLBGameday::Team 30 | name: Yankees 31 | city: New York 32 | league: *al 33 | division: *aleast 34 | code: NYY 35 | file_code: nyy 36 | id: 147 37 | alt_names: 38 | - new york yankee 39 | - nyamlb 40 | :TB: !ruby/object:MLBGameday::Team 41 | name: Rays 42 | city: Tampa Bay 43 | league: *al 44 | division: *aleast 45 | code: TB 46 | file_code: tb 47 | id: 139 48 | alt_names: 49 | - devil rays 50 | - devil ray 51 | - tampa 52 | - tbamlb 53 | :TOR: !ruby/object:MLBGameday::Team 54 | name: Blue Jays 55 | city: Toronto 56 | league: *al 57 | division: *aleast 58 | code: TOR 59 | file_code: tor 60 | id: 141 61 | alt_names: 62 | - bluejay 63 | - jays 64 | - jay 65 | - tormlb 66 | :Central: &alcentral !ruby/object:MLBGameday::Division 67 | name: Central 68 | league: *al 69 | id: 202 70 | teams: 71 | :CLE: !ruby/object:MLBGameday::Team 72 | name: Indians 73 | city: Cleveland 74 | league: *al 75 | division: *alcentral 76 | code: CLE 77 | file_code: cle 78 | id: 114 79 | :CWS: !ruby/object:MLBGameday::Team 80 | name: White Sox 81 | city: Chicago 82 | league: *al 83 | division: *alcentral 84 | code: CWS 85 | file_code: cws 86 | id: 145 87 | :DET: !ruby/object:MLBGameday::Team 88 | name: Tigers 89 | city: Detroit 90 | league: *al 91 | division: *alcentral 92 | code: DET 93 | file_code: det 94 | id: 116 95 | :KC: !ruby/object:MLBGameday::Team 96 | name: Royals 97 | city: Kansas City 98 | league: *al 99 | division: *alcentral 100 | code: KC 101 | file_code: kc 102 | id: 118 103 | alt_names: 104 | - kansas 105 | :MIN: !ruby/object:MLBGameday::Team 106 | name: Twins 107 | city: Minnesota 108 | league: *al 109 | division: *alcentral 110 | code: MIN 111 | file_code: min 112 | id: 142 113 | :West: &alwest !ruby/object:MLBGameday::Division 114 | name: West 115 | league: *al 116 | id: 200 117 | teams: 118 | :LAA: !ruby/object:MLBGameday::Team 119 | name: Angels 120 | city: Anaheim 121 | league: *al 122 | division: *alwest 123 | code: LAA 124 | file_code: ana 125 | id: 108 126 | alt_names: 127 | - ana 128 | - los angeles angel 129 | - los angeles angels 130 | - la angels 131 | - la angel 132 | - laaa 133 | - los angeles angels of anaheim 134 | :HOU: !ruby/object:MLBGameday::Team 135 | name: Astros 136 | city: Houston 137 | league: *al 138 | division: *alwest 139 | code: HOU 140 | file_code: hou 141 | id: 117 142 | :OAK: !ruby/object:MLBGameday::Team 143 | name: Athletics 144 | city: Oakland 145 | league: *al 146 | division: *alwest 147 | code: OAK 148 | file_code: oak 149 | id: 133 150 | alt_names: 151 | - as 152 | :SEA: !ruby/object:MLBGameday::Team 153 | name: Mariners 154 | city: Seattle 155 | league: *al 156 | division: *alwest 157 | code: SEA 158 | file_code: sea 159 | id: 136 160 | :TEX: !ruby/object:MLBGameday::Team 161 | name: Rangers 162 | city: Texas 163 | league: *al 164 | division: *alwest 165 | code: TEX 166 | file_code: tex 167 | id: 140 168 | :NL: &nl !ruby/object:MLBGameday::League 169 | name: National 170 | divisions: 171 | :East: &nleast !ruby/object:MLBGameday::Division 172 | name: East 173 | league: *nl 174 | id: 204 175 | teams: 176 | :ATL: !ruby/object:MLBGameday::Team 177 | name: Braves 178 | city: Atlanta 179 | league: *nl 180 | division: *nleast 181 | code: ATL 182 | file_code: atl 183 | id: 144 184 | :MIA: !ruby/object:MLBGameday::Team 185 | name: Marlins 186 | city: Miami 187 | league: *nl 188 | division: *nleast 189 | code: MIA 190 | file_code: mia 191 | id: 146 192 | alt_names: 193 | - florida 194 | :NYM: !ruby/object:MLBGameday::Team 195 | name: Mets 196 | city: New York 197 | league: *nl 198 | division: *nleast 199 | code: NYM 200 | file_code: nym 201 | id: 121 202 | alt_names: 203 | - new york met 204 | :PHI: !ruby/object:MLBGameday::Team 205 | name: Phillies 206 | city: Philadelphia 207 | league: *nl 208 | division: *nleast 209 | code: PHI 210 | file_code: phi 211 | id: 143 212 | alt_names: 213 | - philly 214 | :WSH: !ruby/object:MLBGameday::Team 215 | name: Nationals 216 | city: Washington 217 | league: *nl 218 | division: *nleast 219 | code: WSH 220 | file_code: was 221 | id: 120 222 | alt_names: 223 | - natinals 224 | :Central: &nlcentral !ruby/object:MLBGameday::Division 225 | name: Central 226 | league: *nl 227 | id: 205 228 | teams: 229 | :CHC: !ruby/object:MLBGameday::Team 230 | name: Cubs 231 | city: Chicago 232 | league: *nl 233 | division: *nlcentral 234 | code: CHC 235 | file_code: chc 236 | id: 112 237 | alt_names: 238 | - chicago cub 239 | :CIN: !ruby/object:MLBGameday::Team 240 | name: Reds 241 | city: Cincinnati 242 | league: *nl 243 | division: *nlcentral 244 | code: CIN 245 | file_code: cin 246 | id: 113 247 | :MIL: !ruby/object:MLBGameday::Team 248 | name: Brewers 249 | city: Milwaukee 250 | league: *nl 251 | division: *nlcentral 252 | code: MIL 253 | file_code: mil 254 | id: 158 255 | :PIT: !ruby/object:MLBGameday::Team 256 | name: Pirates 257 | city: Pittsburgh 258 | league: *nl 259 | division: *nlcentral 260 | code: PIT 261 | file_code: pit 262 | id: 134 263 | alt_names: 264 | - buccos 265 | - bucco 266 | :STL: !ruby/object:MLBGameday::Team 267 | name: Cardinals 268 | city: St. Louis 269 | league: *nl 270 | division: *nlcentral 271 | code: STL 272 | file_code: stl 273 | id: 138 274 | alt_names: 275 | - st louis 276 | :West: &nlwest !ruby/object:MLBGameday::Division 277 | name: West 278 | league: *nl 279 | id: 203 280 | teams: 281 | :ARI: !ruby/object:MLBGameday::Team 282 | name: Diamondbacks 283 | city: Arizona 284 | league: *nl 285 | division: *nlwest 286 | code: ARI 287 | file_code: ari 288 | id: 109 289 | alt_names: 290 | - dbacks 291 | - dback 292 | - az 293 | - "d-backs" 294 | :COL: !ruby/object:MLBGameday::Team 295 | name: Rockies 296 | city: Colorado 297 | league: *nl 298 | division: *nlwest 299 | code: COL 300 | file_code: col 301 | id: 115 302 | :LAD: !ruby/object:MLBGameday::Team 303 | name: Dodgers 304 | city: Los Angeles 305 | league: *nl 306 | division: *nlwest 307 | code: LAD 308 | file_code: la 309 | id: 119 310 | alt_names: 311 | - la 312 | - los angeles dodgers 313 | - los angeles dodger 314 | - la dodger 315 | - la dodgers 316 | :SD: !ruby/object:MLBGameday::Team 317 | name: Padres 318 | city: San Diego 319 | league: *nl 320 | division: *nlwest 321 | code: SD 322 | file_code: sd 323 | id: 135 324 | :SF: !ruby/object:MLBGameday::Team 325 | name: Giants 326 | city: San Francisco 327 | league: *nl 328 | division: *nlwest 329 | code: SF 330 | file_code: sf 331 | id: 137 332 | alt_names: 333 | - san fran 334 | - gigantes 335 | :miscellaneous_teams: 336 | :AAS: !ruby/object:MLBGameday::Team 337 | name: AL All Stars 338 | city: AL 339 | code: AL 340 | file_code: aas 341 | :NAS: !ruby/object:MLBGameday::Team 342 | name: NL All Stars 343 | city: NL 344 | code: NL 345 | file_code: nas 346 | --------------------------------------------------------------------------------