fantasy_football_nerd 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,171 @@
1
+ Fantasy Football Nerd API
2
+ ==========================
3
+
4
+ This is a Ruby Gem for the [Fantasy Football Nerd API](http://www.fantasyfootballnerd.com/api).
5
+
6
+ [Fantasy Football Nerd](http://www.fantasyfootballnerd.com) "takes the 'wisdom of the crowd' to a new level by aggregating the fantasy football rankings of the best fantasy football sites... and weighting the rankings based upon past accuracy."
7
+
8
+ Fantasy Football Nerd provides an API with access to this fantasy football data:
9
+
10
+ * Players List
11
+ * Player Details (including recent articles)
12
+ * Weekly Projections
13
+ * Injury Reports
14
+ * Preseason Draft Rankings (not currently supported)
15
+ * Season Schedule (not currently supported)
16
+
17
+
18
+ Full API access costs $9 for a season subsciption, though if you are a developer with a modicum of interest in Fantasy Football, this is the best $9 you will spend all season.
19
+
20
+
21
+ Cache your data!
22
+ ----------------
23
+ Take heed to the warning on the [Fantasy Football Nerd API page](http://www.fantasyfootballnerd.com):
24
+
25
+ >The data does not generally change more than once or twice per day, so it becomes unnecessary to continually make the same calls. Please store the results locally and reference the cached responses... Your account may be suspended or API access revoked if you are found to be making excessive data calls.
26
+
27
+ Seriously, FFN is not a big operation. Don't abuse their servers.
28
+
29
+ Setup
30
+ =================
31
+ Install the gem:
32
+
33
+ gem install fantasy-football-nerd
34
+
35
+ In plain ol' ruby, require it:
36
+
37
+ ````ruby
38
+ require 'rubygems'
39
+ require 'fantasy-football-nerd'
40
+ ````
41
+
42
+ In rails, add the gem to your gemfile:
43
+
44
+ ````ruby
45
+ gem 'fantasy-football-nerd'
46
+ ````
47
+
48
+ Set your FFN APIKey before making any calls:
49
+
50
+ ````ruby
51
+ FFNerd.api_key = 123456789
52
+ ````
53
+
54
+ API Resources
55
+ ===================
56
+
57
+ Currently, this gem provides access to four feeds:
58
+
59
+ * Player List
60
+ * Player Detail
61
+ * Weekly Projections
62
+ * Injuries
63
+
64
+ Player List
65
+ --------------------------
66
+
67
+ ````ruby
68
+ FFNerd.player_list
69
+ ````
70
+
71
+ Returns an array of players with attributes:
72
+
73
+ ````ruby
74
+ player.player_id
75
+ player.name
76
+ player.position
77
+ player.team
78
+ ````
79
+
80
+ Player Detail
81
+ ------------------------------
82
+
83
+ ````ruby
84
+ player = FFNerd.player_detail(id)
85
+ ````
86
+
87
+ Returns a single player with attributes:
88
+ ````ruby
89
+ player.id
90
+ player.first_name
91
+ player.last_name
92
+ player.team
93
+ player.position
94
+ player.articles
95
+ ````
96
+
97
+ <tt>player.articles</tt> is an array of articles:
98
+
99
+ ````ruby
100
+ article = player.articles.first
101
+ article.title
102
+ article.source
103
+ article.published
104
+ ````
105
+
106
+ Projections
107
+ ---------------
108
+
109
+ ````ruby
110
+ projections = FFNerd.projections(week)
111
+ ````
112
+
113
+ Returns an array of players with attributes:
114
+ ````ruby
115
+ player = projections.first
116
+ player.id
117
+ player.name
118
+ player.team
119
+ player.position
120
+ player.rank
121
+ player.projected_points #equivalent to player.projection.standard
122
+ player.projection.week
123
+ player.projection.standard
124
+ player.projection.standard_low
125
+ player.projection.standard_high
126
+ player.projection.ppr
127
+ player.projection.ppr_low
128
+ player.projection.ppr_high
129
+ ````
130
+
131
+ Injuries
132
+ ---------------------
133
+
134
+ ````ruby
135
+ injuries = FFNerd.injuries(week)
136
+ ````
137
+
138
+ Returns an array of players with attributes:
139
+
140
+ ````ruby
141
+ player = injuries.first
142
+ player.id
143
+ player.name
144
+ player.team
145
+ player.position
146
+ player.injury.week
147
+ player.injury.injury_desc
148
+ player.injury.practice_status_desc
149
+ player.injury.game_status_desc
150
+ player.injury.last_update
151
+ ````
152
+
153
+ Still To Come
154
+ ------------------
155
+ I'll be adding this in the near future:
156
+
157
+ * Better error reporting
158
+ * Schedule
159
+ * Draft Rankings
160
+
161
+ Tests
162
+ ------------------
163
+ The gem includes extensive RSpec tests.
164
+
165
+ Contributors
166
+ -----------------
167
+ This gem was created by:
168
+
169
+ Greg Baugues ([greg@baugues.com](mailto:greg@baugues.com))
170
+
171
+
@@ -0,0 +1,237 @@
1
+ require 'nokogiri'
2
+ require 'open-uri'
3
+ require 'hashie'
4
+
5
+ class FFNerd
6
+
7
+ BASE_URL = "http://api.fantasyfootballnerd.com"
8
+
9
+ #############################################################################
10
+ # URL Generators
11
+ # These methods generate the URLs that will be used for the API calls
12
+ # feed_url() does most of the heavy lifting
13
+ # the others are to make things easier on the developer
14
+ #############################################################################
15
+
16
+ def self.api_key
17
+ @@api_key
18
+ end
19
+
20
+ def self.api_key=(api_key)
21
+ @@api_key = api_key
22
+ end
23
+
24
+ def self.feed_url(feed, params = {} )
25
+ raise "api_key not set" if @@api_key.nil?
26
+ middle =
27
+ case feed
28
+ when :schedule then 'ffnScheduleXML.php'
29
+ when :projections then 'ffnSitStartXML.php'
30
+ when :injuries then 'ffnInjuriesXML.php'
31
+ when :all_players then 'ffnPlayersXML.php'
32
+ when :player then 'ffnPlayerDetailsXML.php'
33
+ end
34
+ url = "#{BASE_URL}/#{middle}?apiKey=#{@@api_key}"
35
+ params.each { |key, value| url += "&#{key}=#{value}" }
36
+ url
37
+ end
38
+
39
+ def self.player_url(player_id)
40
+ feed_url(:player, 'playerId' => 13)
41
+ end
42
+
43
+ def self.projections_url(position, week)
44
+ position = position.to_s.upcase
45
+ feed_url(:projections, 'week' => week, 'position' => position)
46
+ end
47
+
48
+ def self.injuries_url(week)
49
+ feed_url(:injuries, 'week' => week)
50
+ end
51
+
52
+ def self.player_list_url
53
+ feed_url(:all_players)
54
+ end
55
+
56
+
57
+ #############################################################################
58
+ # Resource retreiver
59
+ # Connect to the API resource using the Url builders and Nokogiri
60
+ #############################################################################
61
+
62
+ def self.get_resource(url)
63
+ Nokogiri::HTML(open(url))
64
+ end
65
+
66
+ #############################################################################
67
+ # Player List
68
+ # Grabs a list of all players
69
+ #############################################################################
70
+
71
+
72
+ def self.player_list
73
+ players = []
74
+ url = player_list_url
75
+ doc = get_resource(url)
76
+ doc.css('player').each do |data|
77
+ player = Hashie::Mash.new
78
+ player.id = data.attr('playerid').to_i
79
+ player.name = data.attr('name')
80
+ player.position = data.attr('position')
81
+ player.team = data.attr('team')
82
+ players << player
83
+ end
84
+ players
85
+ end
86
+
87
+ #############################################################################
88
+ # Player Detail
89
+ # grabs player detail and related news articles
90
+ #############################################################################
91
+
92
+
93
+ def self.player_detail(player_id)
94
+ player = Hashie::Mash.new
95
+ url = player_url(player_id)
96
+ doc = get_resource(url)
97
+ player.first_name = doc.css('playerdetails firstname').text
98
+ player.last_name = doc.css('playerdetails lastname').text
99
+ player.team = doc.css('playerdetails team').text
100
+ player.position = doc.css('playerdetails position').text
101
+ player.articles = []
102
+ parse_articles(doc).each { |article| player.articles << article }
103
+ player
104
+ end
105
+
106
+ #used by self.player to get articles
107
+ def self.parse_articles(doc)
108
+ articles = []
109
+ doc.css('article').each do |data|
110
+ article = Hashie::Mash.new
111
+ article.title = data.css('title').text
112
+ article.source = data.css('source').text
113
+ article.published = Date.parse(data.css('published').text)
114
+ articles << article
115
+ end
116
+ articles
117
+ end
118
+
119
+ #############################################################################
120
+ # Projections
121
+ # retrieves weekly projections
122
+ #############################################################################
123
+
124
+ def self.projections(week, position = :all)
125
+ projections = []
126
+ position = position.to_s.upcase
127
+ url = projections_url(position, week)
128
+ doc = get_resource(url)
129
+ doc.css('player').each do |data|
130
+ player = Hashie::Mash.new
131
+ player.name = data.attr('name')
132
+ player.projected_points = data.attr('projectedpoints').to_f
133
+ player.team = data.attr('team')
134
+ player.position = data.attr('position')
135
+ player.id = data.attr('playerid').to_i
136
+ player.rank = data.attr('rank').to_i
137
+
138
+ #create and population player.projection
139
+ player.projection = Hashie::Mash.new
140
+ player.projection.week = data.attr('week').to_i
141
+ projections_map.each do |attribute, xml|
142
+ player.projection[attribute] = data.css("projections #{xml}").text.to_f
143
+ end
144
+
145
+ projections << player
146
+ end
147
+ projections
148
+ end
149
+
150
+ def self.projections_map
151
+ {
152
+ standard: 'standard',
153
+ standard_low: 'standardlow',
154
+ standard_high: 'standardhigh',
155
+ ppr: 'ppr',
156
+ ppr_low: 'pprlow',
157
+ ppr_high: 'pprhigh'
158
+ }
159
+ end
160
+
161
+ #############################################################################
162
+ # Injuries
163
+ # retrieves weekly injuries
164
+ #############################################################################
165
+
166
+
167
+ def self.injuries(week)
168
+ players = []
169
+ url = injuries_url(week)
170
+ doc = get_resource(url)
171
+ #puts doc.css('injury')
172
+ doc.css('injury').each do |data|
173
+ player = Hashie::Mash.new
174
+
175
+ injury_player_data_map.each do |attribute, xml|
176
+ player[attribute] = data.css(xml).text
177
+ end
178
+
179
+ player.injury = Hashie::Mash.new
180
+ injury_data_map.each do |attribute, xml|
181
+ player.injury[attribute] = data.css(xml).text
182
+ end
183
+
184
+ #convert to more appropriate data types
185
+ player.id = player.id.to_i
186
+ player.injury.week = player.injury.week.to_i
187
+ player.injury.last_update = Date.parse(player.injury.last_update)
188
+
189
+ players << player
190
+ end
191
+ players
192
+ end
193
+
194
+
195
+ def self.injury_data_map
196
+ {
197
+ week: 'week',
198
+ injury_desc: 'injurydesc',
199
+ practice_status_desc: 'practicestatusdesc',
200
+ game_status_desc: 'gamestatusdesc',
201
+ last_update: 'lastupdate'
202
+ }
203
+ end
204
+
205
+ def self.injury_player_data_map
206
+ {
207
+ id: 'playerid',
208
+ name: 'playername',
209
+ team: 'team',
210
+ position: 'position'
211
+ }
212
+ end
213
+
214
+ #############################################################################
215
+ # players
216
+ # The one method to rule them all
217
+ #############################################################################
218
+
219
+ def self.players(week, position = :all)
220
+ players = {}
221
+
222
+ FFNerd.projections(week).each do |player|
223
+ player.injured = false
224
+ players[player.id] = player
225
+ end
226
+
227
+ FFNerd.injuries(week).each do |player|
228
+ raise if players[player.id].nil?
229
+ players[player.id].injured = true
230
+ players[player.id].injury = player.injury
231
+ end
232
+
233
+ players.values
234
+ end
235
+
236
+
237
+ end
@@ -0,0 +1,182 @@
1
+ require 'spec_helper.rb'
2
+ require_relative '../lib/fantasy_football_nerd.rb'
3
+
4
+ describe 'Fantasy Football Nerd Gem' do
5
+ before (:each) do
6
+ FFNerd.api_key = '123456789'
7
+ end
8
+
9
+ describe 'feed_url' do
10
+ it 'should generate a url for feeds with an api key' do
11
+ FFNerd.feed_url(:schedule).should =~ /ffnScheduleXML.php/
12
+ FFNerd.feed_url(:projections).should =~ /ffnSitStartXML.php/
13
+ FFNerd.feed_url(:injuries).should =~ /ffnInjuriesXML.php/
14
+ FFNerd.feed_url(:all_players).should =~ /ffnPlayersXML.php/
15
+ FFNerd.feed_url(:player).should =~ /ffnPlayerDetailsXML.php/
16
+ FFNerd.feed_url(:schedule).should =~ /apiKey=\d+/
17
+ end
18
+
19
+ it 'should take parameters' do
20
+ url = FFNerd.feed_url(:schedule, week: 12)
21
+ url.should =~ /&week=12/
22
+ end
23
+ end
24
+
25
+ #############################################################################
26
+ # Resource Retrieval Helpers
27
+ #############################################################################
28
+
29
+ describe 'url builders' do
30
+ it 'should get a url for details on a specific player' do
31
+ url = FFNerd.player_url(13)
32
+ url.should =~ /ffnPlayerDetailsXML.php\?apiKey=\d+&playerId=13/
33
+ end
34
+
35
+ it 'should get a url for a week\'s projections' do
36
+ url = FFNerd.projections_url(:all, 1)
37
+ url.should =~ /ffnSitStartXML.php\?apiKey=\d+&week=1&position=ALL/
38
+ end
39
+
40
+ it 'should get an injury url' do
41
+ url = FFNerd.injuries_url(1)
42
+ url.should =~ /ffnInjuriesXML.php\?apiKey=\d+&week=1/
43
+ end
44
+
45
+ it 'should get a list of all players' do
46
+ url = FFNerd.player_list_url
47
+ url.should =~ /ffnPlayersXML.php\?apiKey=\d+/
48
+ end
49
+ end
50
+
51
+
52
+ it 'should return a resource' do
53
+ VCR.use_cassette('player_list') do
54
+ url = FFNerd.player_list_url
55
+ FFNerd.get_resource(url).should be_true
56
+ end
57
+ end
58
+ #############################################################################
59
+ # Player Detail
60
+ #############################################################################
61
+
62
+ it 'should get player detail' do
63
+ VCR.use_cassette('player_detail') do
64
+ player = FFNerd.player_detail(13)
65
+ player.first_name.should == "Tom"
66
+ player.last_name.should == "Brady"
67
+ player.team.should == "NE"
68
+ player.position.should == "QB"
69
+ player.articles.first.published.should == Date.new(2012, 8, 10)
70
+ end
71
+ end
72
+
73
+ it 'should get player articles' do
74
+ VCR.use_cassette('player_detail') do
75
+ url = FFNerd.player_url(13)
76
+ player_doc = FFNerd.get_resource(url)
77
+ articles = FFNerd.parse_articles(player_doc)
78
+ articles.should be_a Array
79
+ articles.first.title.should == "New England Patriots best New Orleans Saints, 7-6"
80
+ articles.first.source.should == "http://www.nfl.com/goto?id=0ap2000000048294"
81
+ articles.first.published.should == Date.new(2012, 8, 10)
82
+ end
83
+ end
84
+
85
+ #############################################################################
86
+ # Injuries
87
+ #############################################################################
88
+
89
+ it 'should get player data from the injury feed' do
90
+ VCR.use_cassette('injuries') do
91
+ player = FFNerd.injuries(1).first
92
+ test_values(player,
93
+ id: 1242,
94
+ name: 'Alfonso Smith',
95
+ team: 'ARI',
96
+ position: 'RB'
97
+ )
98
+ end
99
+ end
100
+
101
+ it 'should get injury data from the injury feed' do
102
+ VCR.use_cassette('injuries') do
103
+ player = FFNerd.injuries(1).first
104
+ test_values(player.injury,
105
+ week: 1,
106
+ injury_desc: 'Hamstring',
107
+ practice_status_desc: 'Full Practice',
108
+ game_status_desc: 'Good chance to play',
109
+ last_update: Date.parse('2011-09-12')
110
+ )
111
+ end
112
+ end
113
+
114
+ #############################################################################
115
+ # Player List
116
+ #############################################################################
117
+
118
+ it 'player_list should return player data' do
119
+ VCR.use_cassette('player_list') do
120
+ players = FFNerd.player_list
121
+ players.size.should == 1170
122
+ test_values(players.first,
123
+ name: "Derek Anderson",
124
+ position: "QB",
125
+ team: "CAR",
126
+ id: 2
127
+ )
128
+ end
129
+ end
130
+
131
+ #############################################################################
132
+ # Projections
133
+ #############################################################################
134
+
135
+ it 'should retrieve player data from the projection feed' do
136
+ VCR.use_cassette('projections') do
137
+ projections = FFNerd.projections(3, :all)
138
+ player = projections.first
139
+ test_values(player,
140
+ name: "Ray Rice",
141
+ projected_points: 19.60,
142
+ team: "BAL",
143
+ position: "RB",
144
+ id: 269,
145
+ rank: 1
146
+ )
147
+ end
148
+ end
149
+
150
+ it 'should retrieve projection data from the projection feed' do
151
+ VCR.use_cassette('projections') do
152
+ player = FFNerd.projections(3).first
153
+ test_values(player.projection,
154
+ week: 3,
155
+ standard: 19.60,
156
+ standard_low: 15.60,
157
+ standard_high: 27.20,
158
+ ppr: 22.10,
159
+ ppr_low: 18.25,
160
+ ppr_high: 31.20
161
+ )
162
+ end
163
+ end
164
+
165
+ #############################################################################
166
+ # Master Player Method
167
+ # Combines injury and projection data into a single call
168
+ #############################################################################
169
+
170
+ describe 'Master Player Method' do
171
+
172
+ it 'should combine injury and projection data' do
173
+ with_stub_feeds do
174
+ player = FFNerd.players(1).first
175
+ player.position.should == 'RB'
176
+ player.injured.should be_true
177
+ player.projection.standard.should == 26
178
+ end
179
+ end
180
+
181
+ end
182
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fantasy_football_nerd
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Greg Baugues
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: hashie
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: nokogiri
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: Fantasy Football Nerd API wrapper
47
+ email: greg@baugues.com
48
+ executables: []
49
+ extensions: []
50
+ extra_rdoc_files: []
51
+ files:
52
+ - README.md
53
+ - lib/fantasy_football_nerd.rb
54
+ - spec/fantasy_football_nerd_spec.rb
55
+ homepage: http://www.baugues.com
56
+ licenses: []
57
+ post_install_message:
58
+ rdoc_options: []
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ requirements: []
74
+ rubyforge_project: fantasy_football_nerd
75
+ rubygems_version: 1.8.18
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: Fantasy Football Nerd API wrapper
79
+ test_files: []