f1results 0.6 → 3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 1b051ec7bbb7427df68b608f368ec9da378563ad
4
- data.tar.gz: 7e0c83eaae83f0f033c0bd6137819b6d9f2e5fed
2
+ SHA256:
3
+ metadata.gz: aa2c935bee2392688a8b77b2c56668778bb6b84525c3fb6ea4331d5520675d59
4
+ data.tar.gz: 0a035e5ce0d87d87dad070597b860cdb33e2a32cb77f0c48e5b5f9bf4968f8b8
5
5
  SHA512:
6
- metadata.gz: 81e62187f6284f0a4449a31ca52e676b390e1dbb1ecbe946074f1020b139be6f628a2caee888582ec18ebb2ba0fb959ccbeff78a1adcd24a1c1565e76a046a32
7
- data.tar.gz: b69492c988f8047988587a10097f0577ea3be5b8a19b6e3614249040f6917e3e092120361e97d848be6ffa0e2169153df71ff702d54d73882588e1e5ef0feb7d
6
+ metadata.gz: 7664c1698d0b058b1e7a2da0889e322869eac9fbc59c3589297690f843e5c4fcb38867b78448aa50aace0f9d73b32ec1415017f78f443d451497d98522c31235
7
+ data.tar.gz: d5deaedc384e08a0f02434cca1bd1e902c8b276b2bbf4d324ebc4b74ff44c1f51ab6709ea9e6df5ee3e5b1580052da5069b3eefd77ab4a6eea3f21683096a327
data/Rakefile CHANGED
@@ -1,10 +1,58 @@
1
- require 'bundler/setup'
2
- require 'rake'
3
- require 'rake/testtask'
1
+ require "bundler/setup"
2
+ require "rake"
3
+ require "rake/testtask"
4
+ require "./test/lib/fixtures"
5
+ require "open-uri"
6
+ require "fileutils"
7
+ require "tempfile"
4
8
 
5
9
  task default: :test
6
10
 
7
11
  Rake::TestTask.new do |t|
8
- t.libs << 'test/lib'
9
- t.pattern = 'test/*_test.rb'
12
+ t.libs << "test/lib"
13
+ t.pattern = "test/*_test.rb"
14
+ t.warning = false
10
15
  end
16
+
17
+ def fixture_downloads
18
+ Fixtures::STUBS.flat_map do |_name, mappings|
19
+ mappings.filter_map do |path, fixture|
20
+ next if fixture.is_a?(Integer)
21
+
22
+ {
23
+ url: URI.join(F1Results::BASE_URL, path).to_s,
24
+ destination: File.join(Fixtures::FIXTURES_DIR, fixture)
25
+ }
26
+ end
27
+ end
28
+ end
29
+
30
+ namespace :fixtures do
31
+ desc "List fixture URLs and destinations without downloading them"
32
+ task :list do
33
+ fixture_downloads.each do |download|
34
+ puts "#{download[:url]} => #{download[:destination]}"
35
+ end
36
+ end
37
+
38
+ desc "Download fixtures from formula1.com"
39
+ task :download do
40
+ WebMock.disable!
41
+ FileUtils.mkdir_p(Fixtures::FIXTURES_DIR)
42
+
43
+ fixture_downloads.each do |download|
44
+ puts "Downloading #{download[:url]} => #{download[:destination]}"
45
+
46
+ Tempfile.create(["f1results-fixture-", ".html"], Fixtures::FIXTURES_DIR) do |temporary|
47
+ URI.open(download[:url]) do |remote_file|
48
+ IO.copy_stream(remote_file, temporary)
49
+ end
50
+ temporary.close
51
+ FileUtils.mv(temporary.path, download[:destination])
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ desc "Download fixtures from formula1.com (alias for fixtures:download)"
58
+ task download_fixtures: "fixtures:download"
data/bin/f1results CHANGED
@@ -3,54 +3,59 @@
3
3
  require 'rubygems'
4
4
  require 'optparse'
5
5
  require 'terminal-table'
6
- require File.expand_path('../../lib/f1results.rb', __FILE__)
6
+ require_relative '../lib/f1results'
7
7
 
8
8
  year = Time.now.year
9
- country = ''
9
+ grand_prix = ''
10
10
  event_type = :race
11
11
  url = nil
12
12
 
13
13
  optparse = OptionParser.new do |opts|
14
- opts.on('-y', '--year=YEAR', Integer) { |val| year = val }
15
- opts.on('-c', '--country=COUNTRY', String) { |val| country = val.downcase }
16
- opts.on('-e', '--event=EVENT', String) { |val| event_type = val.downcase.to_sym }
17
- opts.on('-u', '--url=URL', String) { |val| url = val }
14
+ opts.on('-y', '--year=YEAR', Integer) { |val| year = val }
15
+ opts.on('-g', '--grandprix=GRANDPRIX', String) { |val| grand_prix = val.capitalize }
16
+ opts.on('-e', '--event=EVENT', String) { |val| event_type = val.downcase.to_sym }
17
+ opts.on('-u', '--url=URL', String) { |val| url = val }
18
18
  opts.parse!
19
19
  end
20
20
 
21
21
  begin
22
22
  event = if url.nil?
23
- F1Results.fetch(year, country, event_type)
23
+ F1Results.fetch(year, grand_prix, event_type)
24
24
  else
25
25
  F1Results.fetch_with_url(url)
26
26
  end
27
- rescue
28
- event_summary = url || "#{year} #{country} #{event_type}"
29
- puts "No results for #{event_summary}"
27
+ rescue RuntimeError => e
28
+ puts e
30
29
  exit
31
30
  end
32
31
 
33
- title = url.nil? ? "#{event.year} #{event.country_name} #{event.type_name}\n#{event.name}" : event.name
32
+ title = url.nil? ? "#{event.year} #{event.grand_prix} #{event.type_name}\n#{event.name}" : event.name
34
33
  table = Terminal::Table.new title: title, rows: event.to_a
35
34
 
36
35
  if event.practice?
37
- table.headings = %W(Pos Num Driver Team Time Gap Laps)
36
+ table.headings = %W(Pos No Driver Team Time Gap Laps)
38
37
  table.align_column 0, :right
39
38
  table.align_column 1, :right
40
39
  table.align_column 4, :right
40
+ table.align_column 5, :right
41
41
  table.align_column 6, :right
42
42
 
43
43
  elsif event.qualifying?
44
- table.headings = %W(Pos Driver Team Q1 Q2 Q3 Laps)
44
+ table.headings = %W(Pos No Driver Team Q1 Q2 Q3 Laps)
45
45
  table.align_column 0, :right
46
+ table.align_column 1, :right
47
+ table.align_column 4, :right
48
+ table.align_column 5, :right
46
49
  table.align_column 6, :right
50
+ table.align_column 7, :right
47
51
 
48
52
  elsif event.race?
49
- table.headings = %W(Pos Driver Country Team Time/Retired Points)
53
+ table.headings = %W(Pos No Driver Team Laps Time/Retired Points)
50
54
  table.align_column 0, :right
51
- table.align_column 2, :center
55
+ table.align_column 1, :right
52
56
  table.align_column 4, :right
53
57
  table.align_column 5, :right
58
+ table.align_column 6, :right
54
59
  end
55
60
 
56
61
  puts table
@@ -2,103 +2,134 @@ require 'mechanize'
2
2
 
3
3
  module F1Results
4
4
  class Agent < ::Mechanize
5
- attr_accessor :event
6
-
7
- def initialize(event = nil)
8
- if event.nil?
9
- @event = F1Results::Event.new
10
- else
11
- self.event = event
12
- end
5
+ def initialize
13
6
  super
7
+ self.verify_mode = OpenSSL::SSL::VERIFY_NONE
14
8
  end
15
9
 
16
- def fetch_results
17
- return fetch_results_with_url(@default_url)
10
+ def get_url(event)
11
+ @event = event
12
+ return url
18
13
  end
19
14
 
20
- def fetch_results_with_url(url)
21
- begin
22
- get(url)
23
- @event.type = parse_event_type if @event.type.nil?
24
- @event.country = parse_event_country if @event.country.nil?
25
- @event.name = parse_event_title
26
- @event.results = parse_event_results
27
- return @event
28
- rescue Mechanize::ResponseCodeError, Net::HTTPNotFound
29
- raise "No results found at #{url}"
30
- end
15
+ def get_results(new_event)
16
+ @event = new_event
17
+ event.url ||= url
18
+ update_event
19
+ return event
31
20
  end
32
21
 
33
- def event=(event)
34
- path = "content/fom-website/en/championship/results/#{event.year}-race-results/#{event.year}-#{event.country_slug}-results/#{event.type_slug}.html"
35
- @default_url = ::File.join F1Results::BASEURL, path
36
- @event = event
22
+ def get_results_with_url(new_url)
23
+ event.url = new_url
24
+ update_event
25
+ return event
37
26
  end
38
27
 
39
28
  private
40
29
 
41
- def parse_event_type
42
- return page.parser.xpath('//h1[@class="headline"]').text.strip rescue nil
30
+ def event
31
+ @event ||= Event.new
43
32
  end
44
33
 
45
- def parse_event_country
46
- return page.parser.xpath('//a[@class="tag-link"]').text.strip.parameterize rescue nil
47
- end
34
+ def url
35
+ base_uri = URI.join F1Results::BASE_URL, "en/results/#{event.year}/"
36
+ year_uri = URI.join base_uri, 'races'
37
+ begin
38
+ get(year_uri)
39
+ rescue Mechanize::ResponseCodeError, Net::HTTPNotFound
40
+ raise "No results found for #{event.year}"
41
+ end
48
42
 
49
- def parse_event_title
50
- return page.parser.xpath('//a[contains(@class, "level-0")]').text rescue nil
51
- end
43
+ grand_prix_nodes = page.parser.xpath("//table//tbody/tr/td[1]//a[contains(@href, '/races/')]").map do |a|
44
+ # Remove SVG icons from the links
45
+ a2 = a.dup
46
+ a2.search('.//svg').remove
47
+ a2
48
+ end
52
49
 
53
- def parse_event_results
54
- results = []
55
- table = page.parser.xpath('//tbody')
50
+ grand_prix_node = grand_prix_nodes.find { |node| node.text.strip.downcase == event.grand_prix.downcase }
51
+ raise "No grand prix '#{event.grand_prix}' found for #{event.year}" if grand_prix_node.nil?
56
52
 
57
- # Remove driver abbreviation from cell
58
- table.xpath('//span[@class="tla"]').each(&:remove)
53
+ grand_prix_uri = URI.join base_uri, grand_prix_node.attr('href')
59
54
 
60
- # Turn HTML table into an array of arrays
61
- data = table.xpath('//tr').map do |row|
62
- row.xpath('./td|./th').map do |cell|
63
- cell = cell.text.gsub(/[[:space:]]+/, ' ').strip
64
- cell.blank? ? nil : cell
65
- end
55
+ begin
56
+ get(grand_prix_uri)
57
+ rescue Mechanize::ResponseCodeError, Net::HTTPNotFound
58
+ raise "Error fetching #{grand_prix_uri}"
66
59
  end
67
60
 
68
- # Remove rows that have the cell "Q1 107% Time"
69
- regex = /107%/
70
- data.reject! { |row| row.any? { |cell| regex =~ cell } }
61
+ event_names = {
62
+ "race result" => :race_result_node,
63
+ "fastest laps" => :fastest_laps_node,
64
+ "pit stop summary" => :pit_stop_summary_node,
65
+ "starting grid" => :starting_grid_node,
66
+ "overall qualifying" => :overall_qualifying_node,
67
+ "qualifying" => :qualifying_node,
68
+ "practice 3" => :practice3_node,
69
+ "practice 2" => :practice2_node,
70
+ "practice 1" => :practice1_node,
71
+ "sprint" => :sprint_node,
72
+ "sprint grid" => :sprint_grid_node,
73
+ "sprint qualifying" => :sprint_qualifying_node
74
+ }
75
+
76
+ event_nodes = page.parser.xpath("//menu[@aria-labelledby='sidebar-dropdown']//li/a").map do |a|
77
+ # Remove SVG icons from the links
78
+ a2 = a.dup
79
+ a2.search('.//svg').remove
80
+ a2
81
+ end
71
82
 
72
- header = parse_table_header(data.shift)
83
+ # Create a hash to store the nodes
84
+ nodes = {}
85
+ event_names.each do |name, key|
86
+ nodes[key] = event_nodes.find { |node| node.text.strip.downcase == name }
87
+ end
73
88
 
74
- result_class = case
75
- when @event.practice?
76
- PracticeResult
77
- when @event.qualifying?
78
- QualifyingResult
89
+ # TODO: add support for Starting Grid, Warm Up, Pit Stop Summary, Fastest Laps
90
+ node = case
91
+ when event.race?
92
+ nodes[:race_result_node]
93
+ when event.qualifying?
94
+ nodes[:qualifying_node] || nodes[:overall_qualifying_node]
95
+ when event.practice3?
96
+ nodes[:practice3_node]
97
+ when event.practice2?
98
+ nodes[:practice2_node]
99
+ when event.practice1?
100
+ nodes[:practice1_node]
79
101
  else
80
- RaceResult
102
+ raise "Unsupported event type '#{event.type}'"
81
103
  end
82
104
 
83
- data.each_with_index do |row, i|
84
- hash = Hash[header.zip(row)]
85
- hash[:index] = i
105
+ raise "No results for event type '#{event.type}' at #{event.year} #{event.grand_prix}" if node.nil?
86
106
 
87
- result = result_class.new(hash)
88
- results << result
107
+ uri = URI.join base_uri, node.attr('href')
108
+ return uri.to_s
109
+ end
110
+
111
+ def update_event
112
+ begin
113
+ get(event.url)
114
+ rescue Mechanize::ResponseCodeError, Net::HTTPNotFound
115
+ raise "No results found at '#{url}'"
89
116
  end
90
117
 
91
- return results
118
+ new_event = Parser.new(page).parse
119
+ event.type ||= new_event.type
120
+ validate_event(new_event)
121
+
122
+ event.grand_prix ||= new_event.grand_prix
123
+ event.circuit ||= new_event.circuit
124
+ event.name ||= new_event.name
125
+ event.results = new_event.results
92
126
  end
93
127
 
94
- # Turn array of words to symbols
95
- def parse_table_header(header)
96
- header.map do |cell|
97
- # Fix i18n cells that look like this
98
- # {'Position' @ i18n}, {'Driver' @ i18n}, ...
99
- cell = cell.match(/(')(.+)(')/)[2] if /i18n/ =~ cell
100
- cell.to_s.strip.parameterize('_').to_sym
128
+ def validate_event(new_event)
129
+ if event.type != new_event.type
130
+ raise "Results at '#{url}' are returning from '#{new_event.type_name}', not the requested '#{event.type_name}'"
101
131
  end
102
132
  end
133
+
103
134
  end
104
135
  end
@@ -1,46 +1,40 @@
1
- require 'active_support/core_ext/string'
2
-
3
1
  module F1Results
4
2
  class Event
5
- attr_accessor :year, :country, :type, :name, :results
6
-
7
- TYPE_ALIASES = {
8
- p1: :practice1,
9
- p2: :practice2,
10
- p3: :practice3,
11
- q: :qualifying,
12
- r: :race
13
- }
3
+ attr_accessor :year, :grand_prix, :circuit, :type, :name, :results, :url
14
4
 
15
5
  def initialize(args = {})
16
6
  @results = []
17
7
  args.each { |k,v| send("#{k}=", v) }
18
8
  end
19
9
 
20
- def country_name
21
- @country.to_s.titleize
10
+ def grand_prix_slug
11
+ grand_prix.strip.downcase.gsub(/[:space:]+/, '-')
22
12
  end
23
13
 
24
- def country_slug
25
- @country.to_s.parameterize
14
+ # Human readable type, e.g. "Practice 1", "Qualifying", "Starting Grid"
15
+ def type_name
16
+ @type.to_s
17
+ .gsub(/\d/, ' \0')
18
+ .gsub('_', ' ')
19
+ .split(' ')
20
+ .map(&:capitalize)
21
+ .join(' ')
26
22
  end
27
23
 
28
- def type=(type)
29
- type = type.to_s.downcase.gsub(' ', '').to_sym
30
- @type = TYPE_ALIASES[type] || type
24
+ def practice?
25
+ /^practice(1|2|3)$/ =~ @type.to_s
31
26
  end
32
27
 
33
- # Human readable type, e.g. "Practice 1", "Qualifying"
34
- def type_name
35
- @type.to_s.gsub(/\d/, ' \0').capitalize
28
+ def practice1?
29
+ @type == :practice1
36
30
  end
37
31
 
38
- def type_slug
39
- type_name.parameterize
32
+ def practice2?
33
+ @type == :practice2
40
34
  end
41
35
 
42
- def practice?
43
- /^practice(1|2|3)$/ =~ @type.to_s
36
+ def practice3?
37
+ @type == :practice3
44
38
  end
45
39
 
46
40
  def qualifying?
@@ -55,21 +49,25 @@ module F1Results
55
49
  @results.map(&:to_a)
56
50
  end
57
51
 
58
- def winner
59
- @results.first.driver
52
+ def [](i)
53
+ @results[i]
54
+ end
55
+
56
+ def winning
57
+ self[0]
60
58
  end
61
59
 
62
- def loser
63
- @results.last.driver
60
+ def losing
61
+ self[-1]
64
62
  end
65
63
 
66
- def fetch_results
67
- agent = F1Results::Agent.new(self)
68
- agent.fetch_results
64
+ def get_results
65
+ agent = F1Results::Agent.new
66
+ agent.get_results(self)
69
67
  end
70
68
 
71
- def fetch_results_with_url(url)
72
- agent = F1Results::Agent.new(self)
69
+ def get_results_with_url(url)
70
+ agent = F1Results::Agent.new
73
71
  agent.fetch_results_with_url(url)
74
72
  end
75
73
  end
@@ -0,0 +1,95 @@
1
+ module F1Results
2
+ class Parser
3
+ def initialize(page)
4
+ @page = page
5
+ @event = Event.new
6
+ end
7
+
8
+ def parse
9
+ @event.name = event_name
10
+ @event.type = event_type
11
+ @event.grand_prix = event_grand_prix
12
+ @event.circuit = event_circuit
13
+ @event.results = event_results
14
+ # TODO: date
15
+ return @event
16
+ end
17
+
18
+ private
19
+
20
+ def event_name
21
+ return @page.parser.at_xpath('//h1').text.gsub(/[[:space:]]+/, ' ').strip
22
+ end
23
+
24
+ def event_type
25
+ if m = @event.name.match(/(?:.+) - (.+)/)
26
+ result = m[1]
27
+ .gsub(/(?<=RACE )RESULT/i, '')
28
+ .gsub(/OVERALL(?= QUALIFYING)/i, '')
29
+ .gsub(/(?<=PRACTICE)( )(?=[1-3])/i, '')
30
+ .sub(/(?<=QUALIFYING)\s*\d+\z/i, '') # strip numbers for Qualifying
31
+ .strip
32
+ .downcase
33
+ result.to_sym
34
+ end
35
+ end
36
+
37
+ def event_grand_prix
38
+ node = @page.parser.at_xpath('(//dialog)[3]//a[.//title[text()="Active"]]')
39
+ node.xpath('.//svg').remove
40
+
41
+ return node.text.strip
42
+ end
43
+
44
+ def event_circuit
45
+ node = @page.parser.at_xpath('//h1/../../../../../div/following-sibling::div[1]//p[2]')
46
+ return node.text
47
+ end
48
+
49
+ def event_results
50
+ results = []
51
+ tbody = @page.parser.at_xpath('//tbody')
52
+
53
+ # Remove driver abbreviation from driver cell
54
+ tbody.xpath('.//span[@class="md:hidden"]').each(&:remove)
55
+
56
+ # Turn HTML tbody into an array of arrays
57
+ data = tbody.xpath('.//tr').map do |row|
58
+ row.xpath('./td|./th').map do |cell|
59
+ cell = cell.text.gsub(/[[:space:]]+/, ' ').strip
60
+ cell.empty? ? nil : cell
61
+ end
62
+ end
63
+
64
+ header = @page.parser.xpath('//thead//th').map do |cell|
65
+ cell.text.to_s
66
+ .gsub(/\./, '') # Pos. -> Pos
67
+ .gsub(/[[:space:]]+/, '')
68
+ .gsub(/\/.*/, '') # Time/Retired -> Time
69
+ .downcase
70
+ .to_sym
71
+ end
72
+
73
+ # Set result class type
74
+ result_class = case
75
+ when @event.practice?
76
+ PracticeResult
77
+ when @event.qualifying?
78
+ QualifyingResult
79
+ else
80
+ RaceResult
81
+ end
82
+
83
+ # Make each table row a Result
84
+ data.each_with_index do |row, i|
85
+ hash = Hash[header.zip(row)]
86
+ hash[:position] = i + 1
87
+
88
+ result = result_class.new(hash)
89
+ results << result
90
+ end
91
+
92
+ return results
93
+ end
94
+ end
95
+ end
@@ -1,15 +1,10 @@
1
1
  module F1Results
2
2
  class Result
3
- attr_accessor :index, :position, :driver, :driver_number, :driver_country_abbr, :team, :time, :gap, :laps
3
+ attr_accessor :position, :driver, :driver_number, :driver_country_abbr, :team, :time, :gap, :laps
4
+ attr_reader :position_name
4
5
 
5
- alias :p= :position=
6
- alias :pos= :position=
7
- alias :name= :driver=
8
- alias :no= :driver_number=
9
- alias :country= :driver_country_abbr=
10
- alias :best_time= :time=
11
- alias :race_time= :time=
12
- alias :fastest= :time=
6
+ alias_method :no=, :driver_number=
7
+ alias_method :car=, :team=
13
8
 
14
9
  def initialize(args = {})
15
10
  args.each do |k, v|
@@ -18,16 +13,18 @@ module F1Results
18
13
  end
19
14
  end
20
15
 
21
- def position=(n)
22
- @position = case
16
+ def position_name=(n)
17
+ @position_name = case
23
18
  when n.to_s.empty?
24
19
  nil
25
20
  when n.to_i == 0
26
21
  n
27
22
  else
28
- n.to_i
23
+ @position = n.to_i
29
24
  end
30
25
  end
26
+ alias_method :p=, :position_name=
27
+ alias_method :pos=, :position_name=
31
28
 
32
29
  def driver_number
33
30
  @driver_number.to_i == 0 ? nil : @driver_number.to_i
@@ -38,35 +35,42 @@ module F1Results
38
35
  end
39
36
 
40
37
  def gap
38
+ # TODO: parse gap properly
41
39
  @gap.to_f == 0.0 ? nil : @gap.to_f
42
40
  end
43
41
  end
44
42
 
45
43
  class PracticeResult < Result
46
44
  def to_a
47
- [position, driver_number, driver, team, time, gap, laps]
45
+ [position_name, driver_number, driver, team, time, gap, laps]
48
46
  end
47
+
48
+ # TODO: to_h, to_s
49
49
  end
50
50
 
51
51
  class QualifyingResult < Result
52
52
  attr_accessor :q1, :q2, :q3
53
53
 
54
54
  def to_a
55
- [position, driver, team, q1, q2, q3, laps]
55
+ [position_name, driver_number, driver, team, q1, q2, q3, laps]
56
+ end
57
+
58
+ def q1
59
+ @time || @q1
56
60
  end
57
61
 
58
62
  def time
59
- q3 || q2 || q1
63
+ @q3 || @q2 || @q1 || @time
60
64
  end
61
65
  end
62
66
 
63
67
  class RaceResult < Result
64
68
  attr_accessor :retired, :points
65
69
 
66
- alias :points_awarded= :points=
70
+ alias_method :pts=, :points=
67
71
 
68
72
  def to_a
69
- [position, driver, driver_country_abbr, team, time_or_retired, points]
73
+ [position_name, driver_number, driver, team, laps, time_or_retired, points]
70
74
  end
71
75
 
72
76
  def time_or_retired=(str)
@@ -76,6 +80,7 @@ module F1Results
76
80
  @retired = str
77
81
  end
78
82
  end
83
+ alias_method :time_retired=, :time_or_retired=
79
84
 
80
85
  def time_or_retired
81
86
  time || retired
@@ -85,4 +90,7 @@ module F1Results
85
90
  @points.to_i
86
91
  end
87
92
  end
93
+
94
+ # TODO: PitStop < Result
95
+ # TODO: FastestLap < Result
88
96
  end
@@ -1,3 +1,3 @@
1
1
  module F1Results
2
- VERSION = '0.6'
2
+ VERSION = '3.0'
3
3
  end
data/lib/f1results.rb CHANGED
@@ -1,12 +1,13 @@
1
- require 'f1results/version'
2
- require 'f1results/agent'
3
- require 'f1results/event'
4
- require 'f1results/result'
1
+ require_relative './f1results/version'
2
+ require_relative './f1results/agent'
3
+ require_relative './f1results/parser'
4
+ require_relative './f1results/event'
5
+ require_relative './f1results/result'
5
6
 
6
7
  module F1Results
7
- BASEURL = 'http://www.formula1.com'
8
+ BASE_URL = 'https://www.formula1.com/'
8
9
 
9
- # Get results from formula1.com for a given year, country, and event type
10
+ # Get results from formula1.com for a given year, grand prix, and event type
10
11
  # (race or qualifying)
11
12
  #
12
13
  # F1Results.f1results(2010, 'australia', :qualifying)
@@ -14,14 +15,14 @@ module F1Results
14
15
  # Returns an `F1Results::Event` object which has a method `results`, which
15
16
  # returns multiple objects of type `F1Results::Result`
16
17
 
17
- def self.fetch(year, country, type = :race)
18
- event = Event.new(year: year, country: country, type: type)
19
- event.fetch_results
18
+ def self.fetch(year, grand_prix, type = :race)
19
+ event = Event.new(year: year, grand_prix: grand_prix, type: type)
20
+ event.get_results
20
21
  return event
21
22
  end
22
23
 
23
24
  def self.fetch_with_url(url)
24
25
  agent = Agent.new
25
- return agent.fetch_results_with_url(url)
26
+ return agent.get_results_with_url(url)
26
27
  end
27
28
  end
data/test/agent_test.rb CHANGED
@@ -1,74 +1,84 @@
1
1
  require 'test_helper'
2
2
 
3
- class AgentTest < MiniTest::Test
3
+ class AgentTest < Minitest::Test
4
4
  include Fixtures
5
5
 
6
6
  def setup
7
+ stub_all
7
8
  @agent = F1Results::Agent.new
8
9
  end
9
10
 
10
- def test_get_event_2015_australia_race
11
- event = F1Results::Event.new(year: 2015, country: 'Australia', type: :race)
12
- @agent.event = event
13
- @agent.fetch_results
14
- assert_equal '2015 FORMULA 1 ROLEX AUSTRALIAN GRAND PRIX', event.name
15
- assert_equal 17, event.results.length
16
- assert_equal 'Lewis Hamilton', event.winner
17
- assert_equal 'Kevin Magnussen', event.loser
11
+ def test_get_url_2016_australia_practice1
12
+ event = F1Results::Event.new(year: 2016, grand_prix: 'Australia', type: :practice1)
13
+ url = 'https://www.formula1.com/en/results/2016/races/938/australia/practice/1'
14
+ assert_equal url, @agent.get_url(event)
18
15
  end
19
16
 
20
- def test_get_event_2015_australia_qualifying
21
- event = F1Results::Event.new(year: 2015, country: 'Australia', type: :qualifying)
22
- @agent.event = event
23
- @agent.fetch_results
24
- assert_equal '2015 FORMULA 1 ROLEX AUSTRALIAN GRAND PRIX', event.name
25
- assert_equal 20, event.results.length
26
- assert_equal 'Lewis Hamilton', event.winner
27
- assert_equal 'Roberto Merhi', event.loser
17
+ def test_get_url_2016_australia_qualifying
18
+ event = F1Results::Event.new(year: 2016, grand_prix: 'Australia', type: :qualifying)
19
+ url = 'https://www.formula1.com/en/results/2016/races/938/australia/qualifying'
20
+ assert_equal url, @agent.get_url(event)
28
21
  end
29
22
 
30
- def test_get_event_2015_australia_practice1
31
- event = F1Results::Event.new(year: 2015, country: 'Australia', type: :practice1)
32
- @agent.event = event
33
- @agent.fetch_results
34
- assert_equal '2015 FORMULA 1 ROLEX AUSTRALIAN GRAND PRIX', event.name
35
- assert_equal 16, event.results.length
36
- assert_equal 'Nico Rosberg', event.winner
37
- assert_equal 'Romain Grosjean', event.loser
23
+ def test_get_url_2016_australia_race
24
+ event = F1Results::Event.new(year: 2016, grand_prix: 'Australia', type: :race)
25
+ url = 'https://www.formula1.com/en/results/2016/races/938/australia/race-result'
26
+ assert_equal url, @agent.get_url(event)
38
27
  end
39
28
 
40
- def test_get_event_2015_malaysia_practice2
41
- event = F1Results::Event.new(year: 2015, country: 'Malaysia', type: :practice2)
42
- @agent.event = event
43
- @agent.fetch_results
44
- assert_equal '2015 FORMULA 1 PETRONAS MALAYSIA GRAND PRIX', event.name
45
- assert_equal 20, event.results.length
46
- assert_equal 'Lewis Hamilton', event.winner
47
- assert_equal 'Roberto Merhi', event.loser
29
+ def test_get_url_1984_brazil_qualifying
30
+ event = F1Results::Event.new(year: 1984, grand_prix: 'Brazil', type: :qualifying)
31
+ url = 'https://www.formula1.com/en/results/1984/races/466/brazil/qualifying/0'
32
+ assert_equal url, @agent.get_url(event)
48
33
  end
49
34
 
50
- def test_fetch_results_2015_hungary_race
51
- event = @agent.fetch_results_with_url('http://www.formula1.com/content/fom-website/en/championship/results/2015-race-results/2015-Hungary-results/race.html')
52
- assert_equal 'FORMULA 1 PIRELLI MAGYAR NAGYDÍJ 2015', event.name
53
- assert_equal 'hungary', event.country
54
- assert event.race?
55
- assert_equal 20, event.results.length
56
- assert_equal 'Sebastian Vettel', event.winner
57
- assert_equal 'Nico Hulkenberg', event.loser
35
+ def test_get_url_1984_brazil_race
36
+ event = F1Results::Event.new(year: 1984, grand_prix: 'Brazil', type: :race)
37
+ url = 'https://www.formula1.com/en/results/1984/races/466/brazil/race-result'
38
+ assert_equal url, @agent.get_url(event)
58
39
  end
59
40
 
60
- def test_get_event_with_bad_year
61
- assert_raises RuntimeError do
62
- event = F1Results::Event.new(year: 1900, country: 'Australia', type: :race)
63
- @agent.event = event
64
- @agent.fetch_results
41
+ def test_get_url_1950_indianapolis_500_qualifying
42
+ event = F1Results::Event.new(year: 1950, grand_prix: 'Indianapolis', type: :qualifying)
43
+ url = 'https://www.formula1.com/en/results/1950/races/96/indianapolis/qualifying/0'
44
+ assert_equal url, @agent.get_url(event)
45
+ end
46
+
47
+ def test_get_url_1950_indianapolis_500_race
48
+ event = F1Results::Event.new(year: 1950, grand_prix: 'Indianapolis', type: :race)
49
+ url = 'https://www.formula1.com/en/results/1950/races/96/indianapolis/race-result'
50
+ assert_equal url, @agent.get_url(event)
51
+ end
52
+
53
+ def test_get_results_1950_indianapolis_500_race
54
+ event = F1Results::Event.new(year: 1950, grand_prix: 'Indianapolis', type: :race)
55
+ event = @agent.get_results(event)
56
+ assert_equal 36, event.results.length
57
+ end
58
+
59
+ def test_api
60
+ event = F1Results.fetch(1950, 'Indianapolis', :race)
61
+ assert_equal 36, event.results.length
62
+ end
63
+
64
+ def test_event_with_bad_year
65
+ assert_raise_with_message RuntimeError, "No grand prix 'Australia' found for 1900" do
66
+ event = F1Results::Event.new(year: 1900, grand_prix: 'Australia', type: :race)
67
+ @agent.get_url(event)
68
+ end
69
+ end
70
+
71
+ def test_event_with_bad_country
72
+ assert_raise_with_message RuntimeError, "No grand prix 'New Zealand' found for 2016" do
73
+ event = F1Results::Event.new(year: 2016, grand_prix: 'New Zealand', type: :race)
74
+ @agent.get_url(event)
65
75
  end
66
76
  end
67
77
 
68
- def test_get_event_with_bad_grand_prix
69
- assert_raises RuntimeError do
70
- event = F1Results::Event.new(year: 2015, country: 'New Zealand', type: :race)
71
- event.fetch_results
78
+ def test_event_with_bad_event_name
79
+ assert_raise_with_message RuntimeError, "Unsupported event type 'practice4'" do
80
+ event = F1Results::Event.new(year: 2016, grand_prix: 'Australia', type: :practice4)
81
+ @agent.get_url(event)
72
82
  end
73
83
  end
74
84
  end
data/test/event_test.rb CHANGED
@@ -1,37 +1,31 @@
1
1
  require 'test_helper'
2
2
 
3
- class EventTest < MiniTest::Test
4
- include Fixtures
5
-
3
+ class EventTest < Minitest::Test
6
4
  def setup
7
5
  @event = F1Results::Event.new
8
6
  end
9
7
 
10
- def test_type
11
- @event.type = :qualifying
12
- assert_equal 'qualifying', @event.type_slug
13
- @event.type = :practice3
14
- assert_equal 'practice-3', @event.type_slug
15
- @event.type = :p3
16
- assert_equal :practice3, @event.type
17
- end
18
-
19
8
  def test_type_name
9
+ @event.type = :practice1
10
+ assert_equal 'Practice 1', @event.type_name
20
11
  @event.type = :practice3
21
12
  assert_equal 'Practice 3', @event.type_name
22
13
  @event.type = :qualifying
23
14
  assert_equal 'Qualifying', @event.type_name
24
15
  @event.type = :race
25
16
  assert_equal 'Race', @event.type_name
26
- end
27
-
28
- def test_type_setter_with_humanized_input
29
- @event.type = 'Practice 3'
30
- assert_equal :practice3, @event.type
31
- @event.type = 'Qualifying'
32
- assert_equal :qualifying, @event.type
33
- @event.type = 'Race'
34
- assert_equal :race, @event.type
17
+ @event.type = :starting_grid
18
+ assert_equal 'Starting Grid', @event.type_name
19
+ @event.type = :warm_up
20
+ assert_equal 'Warm Up', @event.type_name
21
+ @event.type = :pit_stop_summary
22
+ assert_equal 'Pit Stop Summary', @event.type_name
23
+ @event.type = :fastest_laps
24
+ assert_equal 'Fastest Laps', @event.type_name
25
+ @event.type = :sprint
26
+ assert_equal 'Sprint', @event.type_name
27
+ @event.type = :sprint_grid
28
+ assert_equal 'Sprint Grid', @event.type_name
35
29
  end
36
30
 
37
31
  def test_type_boolean_methods
@@ -49,11 +43,6 @@ class EventTest < MiniTest::Test
49
43
  refute @event.practice?
50
44
  end
51
45
 
52
- def test_country_name
53
- @event.country = 'great britain'
54
- assert_equal 'Great Britain', @event.country_name
55
- end
56
-
57
46
  def test_to_array
58
47
  @event.results << F1Results::RaceResult.new(position: 1, driver: 'Mark Webber', driver_country_abbr: 'AUS', team: 'Red Bull Racing-Renault', time: '1:25:11.288', points: 2)
59
48
  @event.results << F1Results::RaceResult.new(position: 2, driver: 'Fernando Alonso', driver_country_abbr: 'ESP', team: 'Ferrari', time: '+3.0 secs', points: 1)
@@ -0,0 +1,97 @@
1
+ require 'test_helper'
2
+
3
+ class ParserTest < Minitest::Test
4
+ include Fixtures
5
+
6
+ def test_2016_australia_practice1
7
+ event = events(:event_2016_australia_practice_1)
8
+ assert_equal '2016 FORMULA 1 ROLEX AUSTRALIAN GRAND PRIX - PRACTICE 1', event.name
9
+ assert_equal 'Australia', event.grand_prix
10
+ assert_equal 'Albert Park Grand Prix Circuit, Melbourne', event.circuit
11
+ assert_equal :practice1, event.type
12
+ assert_equal 22, event.results.length
13
+ assert_equal 'Lewis Hamilton', event.winning.driver
14
+ assert_equal 'Carlos Sainz', event.losing.driver
15
+ end
16
+
17
+ def test_2016_australia_qualifying
18
+ event = events(:event_2016_australia_qualifying)
19
+ assert_equal '2016 FORMULA 1 ROLEX AUSTRALIAN GRAND PRIX - QUALIFYING', event.name
20
+ assert_equal 'Australia', event.grand_prix
21
+ assert_equal 'Albert Park Grand Prix Circuit, Melbourne', event.circuit
22
+ assert_equal :qualifying, event.type
23
+ assert_equal 22, event.results.length
24
+
25
+ assert_equal 'Lewis Hamilton', event.winning.driver
26
+ assert_equal 'Pascal Wehrlein', event.losing.driver
27
+ end
28
+
29
+ def test_2016_australia_race
30
+ event = events(:event_2016_australia_race_result)
31
+ assert_equal '2016 FORMULA 1 ROLEX AUSTRALIAN GRAND PRIX - RACE RESULT', event.name
32
+ assert_equal 'Australia', event.grand_prix
33
+ assert_equal 'Albert Park Grand Prix Circuit, Melbourne', event.circuit
34
+ assert_equal :race, event.type
35
+ assert_equal 22, event.results.length
36
+ assert_equal 'Nico Rosberg', event.winning.driver
37
+ assert_equal 'Daniil Kvyat', event.losing.driver
38
+ end
39
+
40
+ def test_1984_brazil_qualifying
41
+ event = events(:event_1984_brazil_qualifying_0)
42
+ assert_equal 'BRAZILIAN GRAND PRIX 1984 - OVERALL QUALIFYING', event.name
43
+ assert_equal 'Brazil', event.grand_prix
44
+ assert_equal 'Autódromo Internacional do Rio de Janeiro, Brazil', event.circuit
45
+ assert_equal :qualifying, event.type
46
+ assert_equal 24, event.results.length
47
+ assert_equal 'Elio de Angelis', event.winning.driver
48
+ assert_equal 'Jonathan Palmer', event.losing.driver
49
+ end
50
+
51
+ def test_1984_brazil_race
52
+ event = events(:event_1984_brazil_race_result)
53
+ assert_equal 'BRAZILIAN GRAND PRIX 1984 - RACE RESULT', event.name
54
+ assert_equal 'Brazil', event.grand_prix
55
+ assert_equal 'Autódromo Internacional do Rio de Janeiro, Brazil', event.circuit
56
+ assert_equal :race, event.type
57
+ assert_equal 24, event.results.length
58
+ assert_equal 'Alain Prost', event.winning.driver
59
+ assert_equal 'Ayrton Senna', event.losing.driver
60
+ end
61
+
62
+ def test_1950_indianapolis_500_qualifying
63
+ event = events(:event_1950_indianapolis_qualifying_0)
64
+ assert_equal '1950 INDIANAPOLIS 500 - QUALIFYING', event.name
65
+ assert_equal 'Indianapolis', event.grand_prix
66
+ assert_equal 'Indianapolis Motor Speedway, United States', event.circuit
67
+ assert_equal :qualifying, event.type
68
+ assert_equal 1, event.results.length
69
+ assert_equal 'Walt Faulkner', event.winning.driver
70
+ assert_equal 'Walt Faulkner', event.losing.driver
71
+ end
72
+
73
+ def test_1950_indianapolis_500_race
74
+ event = events(:event_1950_indianapolis_race_result)
75
+ assert_equal '1950 INDIANAPOLIS 500 - RACE RESULT', event.name
76
+ assert_equal 'Indianapolis', event.grand_prix
77
+ assert_equal 'Indianapolis Motor Speedway, United States', event.circuit
78
+ assert_equal :race, event.type
79
+ # Note: 3 ties, so 36 finishers, 33 positions in this race
80
+ assert_equal 36, event.results.length
81
+ assert_equal 'Johnnie Parsons', event.winning.driver
82
+ assert_equal 'Duke Dinsmore', event.losing.driver
83
+ end
84
+
85
+ def test_2024_belgium_race
86
+ event = events(:event_2024_belgium_race_result)
87
+ assert_equal 'FORMULA 1 ROLEX BELGIAN GRAND PRIX 2024 - RACE RESULT', event.name
88
+ assert_equal 'Belgium', event.grand_prix
89
+ assert_equal 'Circuit de Spa-Francorchamps, Spa-Francorchamps', event.circuit
90
+ assert event.race?
91
+ assert_equal 20, event.results.length
92
+ # Note: George Russell won but was DQ'd, but still shows as first result
93
+ assert_equal 'George Russell', event.winning.driver
94
+ assert_equal 'DQ', event.results[0].position_name
95
+ assert_equal 'Zhou Guanyu', event.losing.driver
96
+ end
97
+ end
data/test/result_test.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class ResultTest < MiniTest::Test
3
+ class ResultTest < Minitest::Test
4
4
  def test_time
5
5
  result = F1Results::RaceResult.new
6
6
  result.time_or_retired = '1:25:11.288'
@@ -30,45 +30,49 @@ class ResultTest < MiniTest::Test
30
30
  end
31
31
 
32
32
  def test_parse_practice
33
- result = F1Results::PracticeResult.new(position: '4', driver: 'Carlos Sainz', team: 'Toro Rosso', time: '1:31.014', laps: '32')
34
- assert_equal 4, result.position
35
- assert_equal 'Carlos Sainz', result.driver
36
- assert_equal 'Toro Rosso', result.team
37
- assert_equal '1:31.014', result.time
38
- assert_equal 32, result.laps
33
+ hash = { pos: '2', no: '26', driver: 'Daniil Kvyat', car: 'Red Bull Racing TAG Heuer', time: '1:30.146', gap: '+0.421s', laps: '14' }
34
+ result = F1Results::PracticeResult.new hash
35
+ assert_equal 2, result.position
36
+ assert_equal 'Daniil Kvyat', result.driver
37
+ assert_equal 'Red Bull Racing TAG Heuer', result.team
38
+ assert_equal '1:30.146', result.time
39
+ assert_equal 14, result.laps
39
40
  end
40
41
 
41
42
  def test_parse_qualifying
42
- result = F1Results::QualifyingResult.new(position: '2', driver: 'Nico Rosberg', team: 'Mercedes', q1: '1:28.906', q2: '1:27.097', q3: '1:26.921', laps: '14')
43
- assert_equal 2, result.position
44
- assert_equal 'Nico Rosberg', result.driver
45
- assert_equal 'Mercedes', result.team
46
- assert_equal '1:28.906', result.q1
47
- assert_equal '1:27.097', result.q2
48
- assert_equal '1:26.921', result.q3
49
- assert_equal 14, result.laps
43
+ hash = { pos: '8', no: '3', driver: 'Daniel Ricciardo', car: 'Red Bull Racing TAG Heuer', q1: '1:26.945', q2: '1:25.599', q3: '1:25.589', laps: '15' }
44
+ result = F1Results::QualifyingResult.new hash
45
+ assert_equal 8, result.position
46
+ assert_equal 'Daniel Ricciardo', result.driver
47
+ assert_equal 'Red Bull Racing TAG Heuer', result.team
48
+ assert_equal '1:26.945', result.q1
49
+ assert_equal '1:25.599', result.q2
50
+ assert_equal '1:25.589', result.q3
51
+ assert_equal 15, result.laps
50
52
  end
51
53
 
52
54
  def test_parse_race
53
- result = F1Results::RaceResult.new(position: '3', driver: 'Sebastian Vettel', driver_country_abbr: 'GER', team: 'Ferrari', time: '+34.523s', points: '15')
55
+ hash = { pos: '3', no: '5', driver: 'Sebastian Vettel', car: 'Ferrari', laps: '57', time_retired: '+9.643s', pts: '15' }
56
+ result = F1Results::RaceResult.new hash
54
57
  assert_equal 3, result.position
55
58
  assert_equal 'Sebastian Vettel', result.driver
56
59
  assert_equal 'Ferrari', result.team
57
- assert_equal '+34.523s', result.time
60
+ assert_equal '+9.643s', result.time
58
61
  assert_equal 15, result.points
59
62
  end
60
63
 
61
64
  def test_parse_qualifying_with_blank_values
62
65
  result = F1Results::QualifyingResult.new(position: '16', driver: 'Marcus Ericsson', team: 'Sauber', q1: '1:31.376', q2: nil, q3: nil, laps: 10)
63
66
  assert_equal '1:31.376', result.q1
64
- assert_equal nil, result.q2
65
- assert_equal nil, result.q3
67
+ assert_nil result.q2
68
+ assert_nil result.q3
66
69
  assert_equal 10, result.laps
67
70
  end
68
71
 
69
72
  def test_race_to_a
70
- result = F1Results::RaceResult.new(position: '3', driver: 'Sebastian Vettel', driver_country_abbr: 'GER', team: 'Ferrari', time: '+34.523s', points: '15')
71
- assert_equal [3, 'Sebastian Vettel', 'GER', 'Ferrari', '+34.523s', 15], result.to_a
73
+ hash = { pos: '3', no: '5', driver: 'Sebastian Vettel', car: 'Ferrari', laps: '57', time_retired: '+9.643s', pts: '15' }
74
+ result = F1Results::RaceResult.new hash
75
+ assert_equal [3, 5, 'Sebastian Vettel', 'Ferrari', 57, '+9.643s', 15], result.to_a
72
76
  end
73
77
 
74
78
  def test_unknown_key_doesnt_raise_error
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: f1results
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.6'
4
+ version: '3.0'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Darren Jeacocke
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2016-03-18 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: mechanize
@@ -16,84 +15,70 @@ dependencies:
16
15
  requirements:
17
16
  - - "~>"
18
17
  - !ruby/object:Gem::Version
19
- version: '2.7'
18
+ version: '2.14'
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - "~>"
25
24
  - !ruby/object:Gem::Version
26
- version: '2.7'
25
+ version: '2.14'
27
26
  - !ruby/object:Gem::Dependency
28
27
  name: terminal-table
29
28
  requirement: !ruby/object:Gem::Requirement
30
29
  requirements:
31
30
  - - "~>"
32
31
  - !ruby/object:Gem::Version
33
- version: '1.4'
32
+ version: '4.0'
34
33
  type: :runtime
35
34
  prerelease: false
36
35
  version_requirements: !ruby/object:Gem::Requirement
37
36
  requirements:
38
37
  - - "~>"
39
38
  - !ruby/object:Gem::Version
40
- version: '1.4'
41
- - !ruby/object:Gem::Dependency
42
- name: activesupport
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '4'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '4'
39
+ version: '4.0'
55
40
  - !ruby/object:Gem::Dependency
56
41
  name: rake
57
42
  requirement: !ruby/object:Gem::Requirement
58
43
  requirements:
59
44
  - - "~>"
60
45
  - !ruby/object:Gem::Version
61
- version: '10.1'
46
+ version: '13.3'
62
47
  type: :development
63
48
  prerelease: false
64
49
  version_requirements: !ruby/object:Gem::Requirement
65
50
  requirements:
66
51
  - - "~>"
67
52
  - !ruby/object:Gem::Version
68
- version: '10.1'
53
+ version: '13.3'
69
54
  - !ruby/object:Gem::Dependency
70
55
  name: minitest
71
56
  requirement: !ruby/object:Gem::Requirement
72
57
  requirements:
73
58
  - - "~>"
74
59
  - !ruby/object:Gem::Version
75
- version: '5.3'
60
+ version: '5.25'
76
61
  type: :development
77
62
  prerelease: false
78
63
  version_requirements: !ruby/object:Gem::Requirement
79
64
  requirements:
80
65
  - - "~>"
81
66
  - !ruby/object:Gem::Version
82
- version: '5.3'
67
+ version: '5.25'
83
68
  - !ruby/object:Gem::Dependency
84
69
  name: webmock
85
70
  requirement: !ruby/object:Gem::Requirement
86
71
  requirements:
87
72
  - - "~>"
88
73
  - !ruby/object:Gem::Version
89
- version: '1.17'
74
+ version: 3.25.1
90
75
  type: :development
91
76
  prerelease: false
92
77
  version_requirements: !ruby/object:Gem::Requirement
93
78
  requirements:
94
79
  - - "~>"
95
80
  - !ruby/object:Gem::Version
96
- version: '1.17'
81
+ version: 3.25.1
97
82
  description: Get F1 results from formula1.com
98
83
  email: dazonic@me.com
99
84
  executables:
@@ -108,16 +93,17 @@ files:
108
93
  - lib/f1results.rb
109
94
  - lib/f1results/agent.rb
110
95
  - lib/f1results/event.rb
96
+ - lib/f1results/parser.rb
111
97
  - lib/f1results/result.rb
112
98
  - lib/f1results/version.rb
113
99
  - test/agent_test.rb
114
100
  - test/event_test.rb
101
+ - test/parser_test.rb
115
102
  - test/result_test.rb
116
103
  homepage: https://github.com/daz/f1results
117
104
  licenses:
118
105
  - MIT
119
106
  metadata: {}
120
- post_install_message:
121
107
  rdoc_options: []
122
108
  require_paths:
123
109
  - lib
@@ -132,9 +118,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
132
118
  - !ruby/object:Gem::Version
133
119
  version: '0'
134
120
  requirements: []
135
- rubyforge_project:
136
- rubygems_version: 2.4.5
137
- signing_key:
121
+ rubygems_version: 3.6.7
138
122
  specification_version: 4
139
123
  summary: F1 Results
140
124
  test_files: []