nfl_data 0.0.14 → 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.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +7 -0
  3. data/.gitignore +3 -3
  4. data/.rspec +1 -0
  5. data/.standard.yml +2 -0
  6. data/.travis.yml +6 -0
  7. data/CHANGELOG.md +7 -0
  8. data/Gemfile +1 -1
  9. data/README.md +94 -22
  10. data/Rakefile +5 -6
  11. data/bin/console +1 -1
  12. data/bin/setup +8 -0
  13. data/lib/nfl_data.rb +10 -19
  14. data/lib/nfl_data/api/player.rb +8 -26
  15. data/lib/nfl_data/api/schedule.rb +19 -0
  16. data/lib/nfl_data/api/statline.rb +8 -22
  17. data/lib/nfl_data/models/game.rb +5 -0
  18. data/lib/nfl_data/models/player.rb +11 -18
  19. data/lib/nfl_data/models/schedule.rb +12 -0
  20. data/lib/nfl_data/models/statline.rb +18 -19
  21. data/lib/nfl_data/my_sports_feeds/client.rb +45 -0
  22. data/lib/nfl_data/my_sports_feeds/players_feed.rb +18 -0
  23. data/lib/nfl_data/my_sports_feeds/seasonal_games_feed.rb +22 -0
  24. data/lib/nfl_data/my_sports_feeds/weekly_player_gamelogs.rb +21 -0
  25. data/lib/nfl_data/parsers/player_parser.rb +20 -93
  26. data/lib/nfl_data/parsers/schedule_parser.rb +20 -0
  27. data/lib/nfl_data/parsers/statline_parser.rb +27 -71
  28. data/lib/nfl_data/version.rb +1 -1
  29. data/nfl_data.gemspec +23 -23
  30. data/spec/api/player_spec.rb +24 -0
  31. data/spec/api/schedule_spec.rb +20 -0
  32. data/spec/api/statline_spec.rb +31 -0
  33. data/spec/models/game_spec.rb +15 -0
  34. data/spec/models/player_spec.rb +42 -0
  35. data/spec/models/schedule_spec.rb +17 -0
  36. data/spec/models/statline_spec.rb +63 -0
  37. data/spec/my_sports_feeds/client_spec.rb +17 -0
  38. data/spec/my_sports_feeds/players_feed_spec.rb +49 -0
  39. data/spec/my_sports_feeds/seasonal_games_feed_spec.rb +41 -0
  40. data/spec/my_sports_feeds/weekly_player_gamelogs_spec.rb +144 -0
  41. data/spec/parsers/player_parser_spec.rb +63 -0
  42. data/spec/parsers/schedule_parser_spec.rb +41 -0
  43. data/spec/parsers/statline_parser_spec.rb +68 -0
  44. data/spec/spec_helper.rb +55 -0
  45. metadata +83 -52
  46. data/.codeclimate.yml +0 -5
  47. data/.rubocop.yml +0 -2
  48. data/lib/nfl_data/api/team.rb +0 -23
  49. data/lib/nfl_data/models/team.rb +0 -38
  50. data/lib/nfl_data/parsers/data/teams.rb +0 -36
  51. data/lib/nfl_data/parsers/parser_helper.rb +0 -6
  52. data/lib/nfl_data/parsers/team_parser.rb +0 -76
  53. data/test/nfl_data/api/player_test.rb +0 -25
  54. data/test/nfl_data/api/statline_test.rb +0 -21
  55. data/test/nfl_data/api/team_test.rb +0 -13
  56. data/test/nfl_data/models/player_test.rb +0 -81
  57. data/test/nfl_data/models/statline_test.rb +0 -121
  58. data/test/nfl_data/models/team_test.rb +0 -43
  59. data/test/nfl_data/parsers/player_parser_test.rb +0 -81
  60. data/test/nfl_data/parsers/statline_parser_test.rb +0 -34
  61. data/test/nfl_data/parsers/team_parser_test.rb +0 -37
  62. data/test/test_helper.rb +0 -14
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NflData
4
+ module MySportsFeeds
5
+ class Client
6
+ attr_reader :base_url, :api_key, :api_host, :api_version, :format
7
+
8
+ def initialize(
9
+ api_host: ENV.fetch("MYSPORTSFEEDS_API_HOST"),
10
+ api_key: ENV.fetch("MYSPORTSFEEDS_API_KEY"),
11
+ api_version: ENV.fetch("MYSPORTSFEEDS_API_VERSION")
12
+ )
13
+ @api_host = api_host
14
+ @api_key = api_key
15
+ @api_version = api_version
16
+ @format = "json"
17
+ @base_url = "#{@api_host}/#{@api_version}/pull/nfl/"
18
+ end
19
+
20
+ def get(endpoint:, params: {})
21
+ request(method: :get, endpoint: endpoint, params: params)
22
+ end
23
+
24
+ private
25
+
26
+ def request(method:, endpoint:, params:)
27
+ request = Typhoeus::Request.new(
28
+ "#{base_url}#{endpoint}.#{format}",
29
+ method: method,
30
+ params: params,
31
+ accept_encoding: "gzip",
32
+ userpwd: "#{api_key}:MYSPORTSFEEDS"
33
+ )
34
+
35
+ # request.on_complete do |response|
36
+ # if response.success?
37
+ # end
38
+ # end
39
+
40
+ response = request.run
41
+ JSON.parse(response.body)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NflData
4
+ module MySportsFeeds
5
+ class PlayersFeed
6
+ attr_reader :client
7
+
8
+ def initialize(client: MySportsFeeds::Client.new)
9
+ @client = client
10
+ end
11
+
12
+ def feed(position: nil)
13
+ params = {position: position}
14
+ client.get(endpoint: "players", params: params)["players"]
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NflData
4
+ module MySportsFeeds
5
+ class SeasonalGamesFeed
6
+ attr_reader :client
7
+
8
+ def initialize(client: MySportsFeeds::Client.new)
9
+ @client = client
10
+ end
11
+
12
+ def feed(season_start_year:)
13
+ response = client.get(endpoint: "#{season_slug(season_start_year)}/games")
14
+ response["games"].map { |data| data["schedule"] }
15
+ end
16
+
17
+ def season_slug(year)
18
+ "#{year}-#{year + 1}-regular"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NflData
4
+ module MySportsFeeds
5
+ class WeeklyPlayerGamelogs
6
+ attr_reader :client
7
+
8
+ def initialize(client: MySportsFeeds::Client.new)
9
+ @client = client
10
+ end
11
+
12
+ def feed(season_start_year:, week:)
13
+ client.get(endpoint: "#{season_slug(season_start_year)}/week/#{week}/player_gamelogs")["gamelogs"]
14
+ end
15
+
16
+ def season_slug(year)
17
+ "#{year}-#{year + 1}-regular"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,101 +1,28 @@
1
- require 'typhoeus'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module NflData
4
- class PlayerParser
5
- include ParserHelper
6
-
7
- attr_reader :base_url
8
-
9
- def initialize
10
- @base_url = 'http://www.nfl.com/players/search?category=position&conferenceAbbr=null&playerType=current&conference=ALL&filter='
11
- end
12
-
13
- def get_by_position(position)
14
- if position == :all
15
- {
16
- quarterbacks: get('quarterback'),
17
- runningbacks: get('runningback'),
18
- wide_receivers: get('widereceiver'),
19
- tight_ends: get('tightend')
20
- }
21
- else
22
- # We have to remove the '_' and 's' because the NFL url has
23
- # singular position names and all are one word.
24
- { position => get(position.to_s.gsub(/s|_/, '')) }
25
- end
26
- end
27
-
28
- private
29
-
30
- def get(position)
31
- page_number = 1
32
- url = "#{@base_url}#{position}&d-447263-p=#{page_number}"
33
- return_val = []
34
-
35
- loop do
36
- players_found = update_or_create_players(url)
37
- return_val.push(players_found[1])
38
- break if players_found[0] == 0
39
- url = url.chomp(page_number.to_s)
40
- page_number += 1
41
- url += page_number.to_s
4
+ module Parsers
5
+ class PlayerParser
6
+ def parse(player_data:)
7
+ player_data.map { |data| data["player"] }.map do |data|
8
+ init_player(data)
9
+ end
42
10
  end
43
11
 
44
- return_val.flatten.map(&:to_hash)
45
-
46
- return_val = return_val.flatten
47
- populate_picture_links(return_val)
48
- return_val.map(&:to_hash)
49
- end
50
-
51
- def update_or_create_players(url)
52
- doc = open(url) { |f| Nokogiri(f) }
53
-
54
- # NFL.com stores players in 2 types of rows.
55
- # css class = odd or even.
56
- all_rows = doc.search('tr.odd') + doc.search('tr.even')
57
- players = all_rows.map { |row| parse_player_from_row(row.search('td')) }
58
- [players.count, players]
59
- end
60
-
61
- def parse_player_from_row(elements)
62
- # Get NFL.com Unique player id
63
- nfl_player_id = elements[2].to_s.split('/')[3]
64
-
65
- # player id is the only one with complicated parsing so we
66
- # can just extract the inner text out of the rest of the elements
67
- elements = elements.map(&:inner_text).map(&:strip)
68
- names = elements[2].split(',').map(&:strip).reverse
69
-
70
- Player.new(
71
- nfl_player_id: nfl_player_id,
72
- position: elements[0],
73
- number: elements[1],
74
- status: elements[3],
75
- team: make_jacksonville_abbreviation_consistent(elements[12]),
76
- first_name: names[0],
77
- last_name: names[1],
78
- full_name: names.join(' '),
79
- profile_link: get_profile_link(nfl_player_id, names[0], names[1])
80
- )
81
- end
82
-
83
- def get_profile_link(nfl_player_id, first_name, last_name)
84
- "http://www.nfl.com/player/#{first_name.gsub(/\s/, '')}#{last_name.gsub(/\s/, '')}/#{nfl_player_id}/profile"
85
- end
86
-
87
- def populate_picture_links(players)
88
- hydra = Typhoeus::Hydra.hydra
89
- players.each do |player|
90
- request = Typhoeus::Request.new(player.profile_link, followlocation: true, accept_encoding: 'gzip')
91
- request.on_complete do |response|
92
- doc = Nokogiri::HTML(response.body)
93
- img_element = doc.search('div.player-photo img').first
94
- player.picture_link = img_element.attributes['src'].value unless img_element.nil?
95
- end
96
- hydra.queue(request)
12
+ private
13
+
14
+ def init_player(data)
15
+ Player.new(
16
+ first_name: data["firstName"],
17
+ last_name: data["lastName"],
18
+ full_name: "#{data["firstName"]} #{data["lastName"]}".chomp,
19
+ position: data["primaryPosition"],
20
+ number: data["jerseyNumber"],
21
+ team: data.dig("currentTeam", "abbreviation").to_s,
22
+ msf_player_id: data["id"],
23
+ image_source: data["officialImageSrc"].to_s
24
+ )
97
25
  end
98
- hydra.run
99
26
  end
100
27
  end
101
28
  end
@@ -0,0 +1,20 @@
1
+ module NflData
2
+ module Parsers
3
+ class ScheduleParser
4
+ def parse(schedule_data:)
5
+ Schedule.new(games: schedule_data.map { |data| init_game(data) })
6
+ end
7
+
8
+ private
9
+
10
+ def init_game(data)
11
+ Game.new(
12
+ week: data["week"],
13
+ home_team: data.dig("homeTeam", "abbreviation"),
14
+ away_team: data.dig("awayTeam", "abbreviation"),
15
+ start_time: data["startTime"]
16
+ )
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,78 +1,34 @@
1
- module NflData
2
- class StatlineParser
3
- def initialize
4
- end
5
-
6
- def get(week, year, stat_type)
7
- case stat_type
8
- when :passing
9
- grab_week(week, year, 'Passing')
10
- when :rushing
11
- grab_week(week, year, 'Rushing')
12
- when :receiving
13
- grab_week(week, year, 'Receiving')
14
- end
15
- end
1
+ # frozen_string_literal: true
16
2
 
17
- private
18
-
19
- def get_player_id_from_profile_url(element)
20
- old_url = 'http://nfl.com' +
21
- element.search('a').first.attributes['href'].value
22
- new_url = ''
23
-
24
- begin
25
- open(old_url) do |resp|
26
- new_url = resp.base_uri.to_s
3
+ module NflData
4
+ module Parsers
5
+ class StatlineParser
6
+ def parse(statline_data:)
7
+ statline_data.map do |data|
8
+ init_statline(data)
27
9
  end
28
- rescue
29
- return nil
30
10
  end
31
11
 
32
- new_url.gsub('http://www.nfl.com', '').to_s.split('/')[3]
33
- end
34
-
35
- def grab_week(weeknum, year, stat_type)
36
- url = 'http://www.nfl.com/stats/weeklyleaders?type=REG' \
37
- "&week=#{weeknum}&season=#{year}&showCategory=#{stat_type}"
38
-
39
- doc = open(url) { |f| Nokogiri(f) }
40
-
41
- odds = doc.search('tr.odd')
42
- evens = doc.search('tr.even')
43
-
44
- all = odds + evens
45
-
46
- all.map do |player_row|
47
- elements = player_row.search('td')
48
-
49
- statline = Statline.new
50
-
51
- statline.nfl_player_id = get_player_id_from_profile_url(elements[0])
52
- statline.week = weeknum
53
- statline.year = year
54
-
55
- if stat_type == 'Rushing'
56
- statline.rush_atts = elements[4].inner_text.strip
57
- statline.rush_yards = elements[5].inner_text.strip
58
- statline.rush_tds = elements[7].inner_text.strip
59
- statline.fumbles = elements[8].inner_text.strip
60
- elsif stat_type == 'Passing'
61
- statline.pass_comp = elements[4].inner_text.strip
62
- statline.pass_att = elements[5].inner_text.strip
63
- statline.pass_yards = elements[6].inner_text.strip
64
- statline.pass_tds = elements[7].inner_text.strip
65
- statline.ints = elements[8].inner_text.strip
66
- statline.qb_rating = elements[11].inner_text.strip
67
- statline.fumbles = elements [10].inner_text.strip
68
- elsif stat_type == 'Receiving'
69
- statline.receptions = elements[4].inner_text.strip
70
- statline.rec_yards = elements[5].inner_text.strip
71
- statline.rec_tds = elements[7].inner_text.strip
72
- statline.fumbles = elements[8].inner_text.strip
73
- end
74
-
75
- statline.to_hash
12
+ private
13
+
14
+ def init_statline(data)
15
+ Statline.new(
16
+ rush_atts: data.dig("stats", "rushing", "rushAttempts") || 0,
17
+ rush_yards: data.dig("stats", "rushing", "rushYards") || 0,
18
+ rush_tds: data.dig("stats", "rushing", "rushTD") || 0,
19
+ fumbles: data.dig("stats", "fumbles", "fumbles") || 0,
20
+ pass_comp: data.dig("stats", "passing", "passCompletions") || 0,
21
+ pass_att: data.dig("stats", "passing", "passAttempts") || 0,
22
+ pass_yards: data.dig("stats", "passing", "passYards") || 0,
23
+ pass_tds: data.dig("stats", "passing", "passTD") || 0,
24
+ ints: data.dig("stats", "interceptions", "interceptions") || 0,
25
+ qb_rating: data.dig("stats", "passing", "qbRating") || 0,
26
+ receptions: data.dig("stats", "receiving", "receptions") || 0,
27
+ rec_yards: data.dig("stats", "receiving", "recYards") || 0,
28
+ rec_tds: data.dig("stats", "receiving", "recTD") || 0,
29
+ msf_game_id: data.dig("game", "id"),
30
+ msf_player_id: data.dig("player", "id")
31
+ )
76
32
  end
77
33
  end
78
34
  end
@@ -1,3 +1,3 @@
1
1
  module NflData
2
- VERSION = '0.0.14'
2
+ VERSION = "0.1.0"
3
3
  end
@@ -1,31 +1,31 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ lib = File.expand_path("../lib", __FILE__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
3
 
5
- require 'nfl_data/version'
4
+ require "nfl_data/version"
6
5
 
7
6
  Gem::Specification.new do |spec|
8
- spec.name = 'nfl_data'
9
- spec.version = NflData::VERSION
10
- spec.authors = ['thetizzo']
11
- spec.email = ['j.m.taylor1@gmail.com']
12
- spec.homepage = 'https://github.com/thetizzo/nfl_data'
13
- spec.license = 'MIT'
14
- spec.summary = 'Parse NFL data like a boss'
15
- spec.description = 'Parse NFL data like a boss'
7
+ spec.name = "nfl_data"
8
+ spec.version = NflData::VERSION
9
+ spec.authors = ["thetizzo"]
10
+ spec.email = ["j.m.taylor1@gmail.com"]
11
+ spec.homepage = "https://github.com/thetizzo/nfl_data"
12
+ spec.license = "MIT"
13
+ spec.summary = "Parse NFL data like a boss"
14
+ spec.description = "Parse NFL data like a boss"
16
15
 
17
- spec.files = `git ls-files -z`.split("\x0")
18
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
- spec.require_paths = ['lib']
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
21
20
 
22
- spec.add_development_dependency 'bundler', '~> 1.16.5'
23
- spec.add_development_dependency 'rake'
24
- spec.add_development_dependency 'minitest', '~> 5.11.3'
25
- spec.add_development_dependency 'vcr', '~> 4.0.0'
26
- spec.add_development_dependency 'webmock', '~> 3.4.2'
27
- spec.add_development_dependency 'rubocop', '~> 0.59.1'
21
+ spec.add_development_dependency "rake", "~> 13.0"
22
+ spec.add_development_dependency "rspec", "~> 3.9"
23
+ spec.add_development_dependency "rspec-resembles_json_matchers", "~> 0.9"
24
+ spec.add_development_dependency "vcr", "~> 4.0.0"
25
+ spec.add_development_dependency "webmock", "~> 3.8"
26
+ spec.add_development_dependency "standard", "~> 0.1"
28
27
 
29
- spec.add_dependency 'typhoeus', '~> 1.3'
30
- spec.add_dependency 'nokogiri', '~> 1.6'
28
+ spec.add_dependency "nokogiri", "~> 1.10"
29
+ spec.add_dependency "typhoeus", "~> 1.4"
30
+ spec.add_dependency "zeitwerk", "~> 2.4"
31
31
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe NflData::Api::Player do
4
+ subject { described_class.new }
5
+
6
+ it "provides the players in json" do
7
+ VCR.use_cassette("msf_players") do
8
+ expect(JSON.parse(subject.players)).to resemble_json(
9
+ "players": [
10
+ {
11
+ "first_name": "B",
12
+ "last_name": "2Anger2",
13
+ "full_name": "B 2Anger2",
14
+ "position": "LB",
15
+ "number": 19,
16
+ "team": "JAX",
17
+ "msf_player_id": 19407,
18
+ "image_source": "google.com"
19
+ }
20
+ ]
21
+ )
22
+ end
23
+ end
24
+ end