f1results 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Darren Jeacocke
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.
data/README.md ADDED
@@ -0,0 +1,23 @@
1
+ # F1Results
2
+
3
+ Get F1 results from formula1.com
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'f1results'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install f1results
18
+
19
+ ## Usage
20
+
21
+ ### Command Line
22
+
23
+ $ f1results <season> [<round>] [-q, --qualifying]
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/setup'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+
5
+ task :default => :test
6
+
7
+ Rake::TestTask.new do |t|
8
+ t.libs << 'test/lib'
9
+ t.pattern = 'test/*_test.rb'
10
+ end
data/bin/f1results ADDED
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'optparse'
5
+ require 'terminal-table'
6
+ require 'f1results'
7
+
8
+ options = {}
9
+
10
+ optparse = OptionParser.new do |opts|
11
+ options[:type] = :race
12
+ opts.on('-q', '--qualifying', 'Qualifying') do
13
+ options[:type] = :qualifying
14
+ end
15
+ end
16
+
17
+ optparse.parse!
18
+
19
+ season = ARGV[0] || Time.now.year
20
+ country = if country = ARGV[1]
21
+ country.to_i == 0 ? country : country.to_i
22
+ else
23
+ :latest
24
+ end
25
+
26
+ begin
27
+ event = F1Results.get(season, country, options[:type])
28
+ rescue Exception => e
29
+ puts e
30
+ exit
31
+ end
32
+
33
+ title = [event.country, event.type.to_s.capitalize, event.grand_prix].join(' ')
34
+ table = Terminal::Table.new :title => title, :rows => event.to_a
35
+
36
+ if event.qualifying?
37
+ cols = %W(Pos Num Driver Team Q1 Q2 Q3 Laps)
38
+ table.align_column 0, :right
39
+ table.align_column 1, :right
40
+ table.align_column 7, :right
41
+
42
+ elsif event.race?
43
+ cols = %W(Pos Num Driver Team Laps Time/Retired Grid Points)
44
+ table.align_column 0, :right
45
+ table.align_column 1, :right
46
+ table.align_column 4, :right
47
+ table.align_column 5, :right
48
+ table.align_column 6, :right
49
+ table.align_column 7, :right
50
+ end
51
+
52
+ table.headings = cols
53
+ puts table
data/lib/f1results.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'f1results/version'
2
+ require 'f1results/agent'
3
+ require 'f1results/event'
4
+ require 'f1results/result'
5
+
6
+ module F1Results
7
+ BASEURL = 'http://www.formula1.com'
8
+
9
+ # Get results from formula1.com for a given season, country, and event type
10
+ # (race or qualifying)
11
+ #
12
+ # F1Results.get(2010, 'australia', :qualifying)
13
+ #
14
+ # Returns an `F1Results::Event` object which has a method `results`, which
15
+ # returns multiple objects of type `F1Results::Result`
16
+
17
+ def self.get(year, country, type = :race)
18
+ agent = F1Results::Agent.new
19
+ agent.get_event(year, country, type)
20
+ end
21
+ end
@@ -0,0 +1,51 @@
1
+ require 'mechanize'
2
+
3
+ module F1Results
4
+ class Agent < ::Mechanize
5
+ def get_event(season, country, type)
6
+ event = Event.new(:season => season, :type => type)
7
+
8
+ begin
9
+ get(::File.join(F1Results::BASEURL, "results/season/#{season}/"))
10
+ rescue Mechanize::ResponseCodeError, 404
11
+ raise "No results for season: #{season}"
12
+ end
13
+
14
+ season_country_link = case
15
+ when country.is_a?(String)
16
+ event.country = country
17
+ page.link_with(:text => event.country)
18
+ when country.is_a?(Integer)
19
+
20
+ # Get the link to the country on the nth row
21
+
22
+ next_page = page.parser.at_xpath("//tr[not(position()=1)][#{country}]/td[1]/a")
23
+ event.country = next_page.text
24
+ page.link_with(:node => next_page)
25
+ when country == :latest
26
+
27
+ # Get the link to the country in the last row where results are present
28
+
29
+ next_page = page.parser.at_xpath('(//tr/td[3][node()])[last()]/../td[1]/a')
30
+ event.country = next_page.text
31
+ page.link_with(:node => next_page)
32
+ end
33
+ raise "Grand Prix not found: #{season} #{country}" if season_country_link.nil?
34
+
35
+ click(season_country_link)
36
+ event.grand_prix = page.parser.at_xpath('//h2').text
37
+
38
+ if event.qualifying?
39
+ grand_prix_link = page.link_with(:text => 'QUALIFYING') || page.link_with(:text => 'SUNDAY QUALIFYING')
40
+ raise "No qualifying results for: #{season} #{country}" if grand_prix_link.nil?
41
+ click(grand_prix_link)
42
+ end
43
+
44
+ table = page.parser.xpath('//table[contains(@class, "raceResults")]')
45
+ raise "No results for: #{season} #{country}" if table.empty?
46
+
47
+ event.parse_results_table(table)
48
+ event
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,49 @@
1
+ module F1Results
2
+ class Event
3
+ attr_accessor :season, :country, :type, :grand_prix, :results
4
+
5
+ def initialize(args)
6
+ args.each { |k,v| send("#{k}=", v) }
7
+ @results = []
8
+ end
9
+
10
+ def country
11
+ @country.split(/(\W)/).map(&:capitalize).join
12
+ end
13
+
14
+ def qualifying?
15
+ @type == :qualifying
16
+ end
17
+
18
+ def race?
19
+ @type == :race
20
+ end
21
+
22
+ def to_a
23
+ @results.map(&:to_a)
24
+ end
25
+
26
+ def winner
27
+ @results.first.driver
28
+ end
29
+
30
+ def loser
31
+ @results.last.driver
32
+ end
33
+
34
+ def parse_results_table(table)
35
+ data = table.xpath('//tr')[1..-1].map do |row|
36
+ row.xpath('./td').map do |col|
37
+ col.text.strip
38
+ end
39
+ end
40
+
41
+ data.each_with_index do |row, i|
42
+ klass = qualifying? ? QualifyingResult : RaceResult
43
+ result = klass.new(row)
44
+ result.index = i + 1
45
+ @results << result unless result.position.nil?
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,79 @@
1
+ module F1Results
2
+ class Result
3
+ attr_accessor :index, :position, :driver, :driver_number, :team, :time, :retired, :laps
4
+
5
+ def initialize(row = nil)
6
+ build(row) unless row.nil?
7
+ end
8
+
9
+ def position=(n)
10
+ @position = case
11
+ when n == ''
12
+ nil
13
+ when n.to_i == 0
14
+ n
15
+ else
16
+ n.to_i
17
+ end
18
+ end
19
+
20
+ def time_or_retired=(str)
21
+ if /^[0-9]|\+/ =~ str
22
+ @time = str
23
+ else
24
+ @retired = str
25
+ end
26
+ end
27
+
28
+ def time_or_retired
29
+ time || retired
30
+ end
31
+
32
+ private
33
+
34
+ def build(row)
35
+ self.position = row[0]
36
+ @driver_number = row[1].to_i
37
+ @driver = row[2]
38
+ @team = row[3]
39
+ end
40
+ end
41
+
42
+ class QualifyingResult < Result
43
+ attr_accessor :q1, :q2, :q3
44
+
45
+ def to_a
46
+ [position, driver_number, driver, team, q1, q2, q3, laps]
47
+ end
48
+
49
+ private
50
+
51
+ def build(row)
52
+ @q1 = row[4]
53
+ if row.length > 5
54
+ @q2 = row[5]
55
+ @q3 = row[6]
56
+ @laps = row[7].to_i
57
+ end
58
+ super
59
+ end
60
+ end
61
+
62
+ class RaceResult < Result
63
+ attr_accessor :grid, :points
64
+
65
+ def to_a
66
+ [position, driver_number, driver, team, laps, time_or_retired, grid, points]
67
+ end
68
+
69
+ private
70
+
71
+ def build(row)
72
+ @laps = row[4].to_i
73
+ self.time_or_retired = row[5]
74
+ @grid = row[6].to_i
75
+ @points = row[7].to_i
76
+ super
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,3 @@
1
+ module F1Results
2
+ VERSION = "0.1"
3
+ end
@@ -0,0 +1,70 @@
1
+ # encoding: utf-8
2
+ require 'test_helper'
3
+
4
+ class AgentTest < MiniTest::Unit::TestCase
5
+ include Fixtures
6
+
7
+ def setup
8
+ @agent = F1Results::Agent.new
9
+ end
10
+
11
+ def test_get_event_2012_great_britain
12
+ event = @agent.get_event(2012, 'Great Britain', :race)
13
+ assert event.race?
14
+ assert_equal 'Great Britain', event.country
15
+ assert_equal '2012 FORMULA 1 SANTANDER BRITISH GRAND PRIX', event.grand_prix
16
+ assert_equal 24, event.results.size
17
+ assert_equal 'Mark Webber', event.winner
18
+ assert_equal 'Vitaly Petrov', event.loser
19
+ end
20
+
21
+ def test_get_event_2012_great_britain_qualifying
22
+ event = @agent.get_event(2012, 'Great Britain', :qualifying)
23
+ assert event.qualifying?
24
+ assert_equal 'Great Britain', event.country
25
+ assert_equal '2012 FORMULA 1 SANTANDER BRITISH GRAND PRIX', event.grand_prix
26
+ assert_equal 24, event.results.size
27
+ assert_equal 'Fernando Alonso', event.winner
28
+ assert_equal 'Charles Pic', event.loser
29
+ end
30
+
31
+ def test_get_event_2005_australia_qualifyng
32
+ event = @agent.get_event(2005, 'Australia', :qualifying)
33
+ assert_equal 'Australia', event.country
34
+ assert_equal "2005 FORMULA 1™ Foster's Australian Grand Prix", event.grand_prix
35
+ assert_equal 20, event.results.size
36
+ assert_equal 'Giancarlo Fisichella', event.winner
37
+ end
38
+
39
+ def test_get_event_1992_hungary
40
+ event = @agent.get_event(1992, 'Hungary', :race)
41
+ assert_equal 'Hungary', event.country
42
+ assert_equal '1992 Hungarian Grand Prix', event.grand_prix
43
+ assert_equal 31, event.results.size
44
+ assert_equal 'Ayrton Senna', event.winner
45
+ end
46
+
47
+ def test_get_event_with_bad_year
48
+ assert_raises RuntimeError, 'Invalid season: 1800' do
49
+ @agent.get_event(1800, 'Australia', :race)
50
+ end
51
+ end
52
+
53
+ def test_get_event_with_bad_grand_prix
54
+ assert_raises RuntimeError, 'Invalid Grand Prix: New Zealand' do
55
+ @agent.get_event(2012, 'New Zealand', :race)
56
+ end
57
+ end
58
+
59
+ def test_get_event_2012_9th
60
+ event = @agent.get_event(2012, 9, :race)
61
+ assert_equal 'Great Britain', event.country
62
+ assert_equal '2012 FORMULA 1 SANTANDER BRITISH GRAND PRIX', event.grand_prix
63
+ end
64
+
65
+ def test_get_event_2012_latest
66
+ event = @agent.get_event(2012, :latest, :race)
67
+ assert_equal 'Hungary', event.country
68
+ assert_equal 'FORMULA 1 ENI MAGYAR NAGYDÍJ 2012', event.grand_prix
69
+ end
70
+ end
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+ require 'test_helper'
3
+
4
+ class ResultTest < MiniTest::Unit::TestCase
5
+ def test_time
6
+ result = F1Results::RaceResult.new
7
+ result.time_or_retired = '1:25:11.288'
8
+ assert_equal '1:25:11.288', result.time
9
+ end
10
+
11
+ def test_relative_time
12
+ result = F1Results::RaceResult.new
13
+ result.time_or_retired = '+3.0 secs'
14
+ assert_equal '+3.0 secs', result.time
15
+ end
16
+
17
+ def test_retired
18
+ result = F1Results::RaceResult.new
19
+ result.time_or_retired = 'Accident'
20
+ assert_equal 'Accident', result.retired
21
+ result.time_or_retired = 'Gear box'
22
+ assert_equal 'Gear box', result.retired
23
+ end
24
+
25
+ def test_parse_race
26
+ result = F1Results::RaceResult.new(['5', '9', 'Kimi Räikkönen', 'Lotus-Renault', '52', '+10.3 secs', '6', '10'])
27
+ assert_equal 5, result.position
28
+ assert_equal 9, result.driver_number
29
+ assert_equal 'Kimi Räikkönen', result.driver
30
+ assert_equal 'Lotus-Renault', result.team
31
+ assert_equal 52, result.laps
32
+ assert_equal '+10.3 secs', result.time
33
+ assert_equal 6, result.grid
34
+ assert_equal 10, result.points
35
+ end
36
+
37
+ def test_parse_qualifying
38
+ result = F1Results::QualifyingResult.new(['1', '5', 'Fernando Alonso', 'Ferrari', '1:46.515', '1:56.921', '1:51.746', '25'])
39
+ assert_equal 1, result.position
40
+ assert_equal 5, result.driver_number
41
+ assert_equal 'Fernando Alonso', result.driver
42
+ assert_equal 'Ferrari', result.team
43
+ assert_equal '1:46.515', result.q1
44
+ assert_equal '1:56.921', result.q2
45
+ assert_equal '1:51.746', result.q3
46
+ assert_equal 25, result.laps
47
+ end
48
+
49
+ def test_race_to_a
50
+ result = F1Results::RaceResult.new(['5', '9', 'Kimi Räikkönen', 'Lotus-Renault', '52', '+10.3 secs', '6', '10'])
51
+ assert_equal [5, 9, 'Kimi Räikkönen', 'Lotus-Renault', 52, '+10.3 secs', 6, 10], result.to_a
52
+ end
53
+ end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: f1results
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Darren Jeacocke
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: mechanize
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: terminal-table
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
+ - !ruby/object:Gem::Dependency
47
+ name: rake
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: minitest
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: webmock
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ description: Get F1 results from formula1.com
95
+ email: dazonic@me.com
96
+ executables:
97
+ - f1results
98
+ extensions: []
99
+ extra_rdoc_files: []
100
+ files:
101
+ - bin/f1results
102
+ - lib/f1results/agent.rb
103
+ - lib/f1results/event.rb
104
+ - lib/f1results/result.rb
105
+ - lib/f1results/version.rb
106
+ - lib/f1results.rb
107
+ - test/agent_test.rb
108
+ - test/result_test.rb
109
+ - Rakefile
110
+ - README.md
111
+ - LICENSE
112
+ homepage: https://github.com/daz/f1results
113
+ licenses: []
114
+ post_install_message:
115
+ rdoc_options: []
116
+ require_paths:
117
+ - lib
118
+ required_ruby_version: !ruby/object:Gem::Requirement
119
+ none: false
120
+ requirements:
121
+ - - ! '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ! '>='
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ requirements: []
131
+ rubyforge_project:
132
+ rubygems_version: 1.8.23
133
+ signing_key:
134
+ specification_version: 3
135
+ summary: F1 Results
136
+ test_files: []