fonecal 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a1fc6ce41a3fc30629c84f13f5e30efd7a818dea
4
- data.tar.gz: 7c1b8008deaa54272b458728323753bfec041e7c
3
+ metadata.gz: 29ab1f8513997afc142589ccbc8caef9493ebf6e
4
+ data.tar.gz: da8893c965adee5e6b737d51ffc190a983269d7b
5
5
  SHA512:
6
- metadata.gz: 2ed0c7605dd37c7e448c805ffa974e033448abc3fa56ec6e6455714a5108e9f52c867fc60cb19fbaf9dfa638c1287933724e340bb4d34746192384b1560ca237
7
- data.tar.gz: 0961b72dc47db6b73e84e5522fabfcf02379477e9eaba9f5e5a6e4f71da52ddb376a67490a1cb52e4853a17c7014836b9071f808add855f0a2ae9b27b3a7c4de
6
+ metadata.gz: ef0e2346e4ad38d7b1c68b4a58f9f8ea776cf6de54d20a427c8c496b53fd9e5e31ccba3c3de4626a468851e689538312f72ce8a17ded68b3ec63258a0b2c467c
7
+ data.tar.gz: e0c97a24373fd76265b29ad3463eb0f729644a09bb9c6837942f68d420787919aa754f635b0d86fca77b4695b24b078c306836071759e7680aaae0137d0144c5
data/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # Fonecal
2
2
 
3
- TODO: Write a gem description
3
+ Fonecal parses [formula1.com](http://www.formula1.com/) for each Grand Prix and outputs an iCalendar file with every qualifying, practice, and race session for this year's 2014 Formula One season. All event times are converted to UTC time, allowing calendars to convert the event time to the user's current timezone.
4
+
5
+ The latest version of the calendar is hosted here: [martinbmadsen.dk/files/f1cal.ics](http://martinbmadsen.dk/files/f1cal.ics), and can be subscribed to in most calendar applications.
6
+
7
+ Note: Most users do not need to read past this point.
4
8
 
5
9
  ## Installation
6
10
 
@@ -14,11 +18,22 @@ And then execute:
14
18
 
15
19
  Or install it yourself as:
16
20
 
17
- $ gem install fonecal
21
+ $ gem install fonecal
18
22
 
19
23
  ## Usage
20
24
 
21
- TODO: Write usage instructions here
25
+ Simply ``require 'fonecal'`` and call
26
+
27
+ $ Fonecal.create_ical
28
+
29
+ To create an iCalendar file in the current directory, readable by your favorite text editor. It is then ready to be imported in a calendar application.
30
+
31
+ ## TODO
32
+ A list of stuff I (might) eventually do.
33
+
34
+ - [ ] fix tests
35
+ - [ ] create a better CLI exposing more features
36
+ - [ ] add documentation
22
37
 
23
38
  ## Contributing
24
39
 
@@ -4,27 +4,27 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'fonecal/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "fonecal"
7
+ spec.name = 'fonecal'
8
8
  spec.version = Fonecal::VERSION
9
- spec.authors = ["Martin Madsen"]
10
- spec.email = ["martin2madsen@gmail.com"]
11
- spec.description = %q{f1cal generates an iCalendar file for the 2014 Formula 1 season.}
9
+ spec.authors = ['Martin Bjeldbak Madsen']
10
+ spec.email = ['martinbmadsen@gmail.com']
11
+ spec.description = %q{fonecal generates an iCalendar file for the 2014 Formula 1 season.}
12
12
  spec.summary = %q{Crawls the Grand Prix list at formula1.com and builds an iCalendar file with events in UTC}
13
- spec.homepage = "https://github.com/Fapper/f1cal"
14
- spec.license = "MIT"
13
+ spec.homepage = 'https://github.com/Fapper/f1cal'
14
+ spec.license = 'MIT'
15
15
 
16
16
  spec.files = `git ls-files`.split($/)
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
19
+ spec.require_paths = ['lib']
20
20
 
21
- spec.add_development_dependency "bundler", "~> 1.3"
22
- spec.add_development_dependency "rake", "~> 10.1"
23
- spec.add_development_dependency "rspec", "~> 2.14"
21
+ spec.add_development_dependency 'bundler', '~> 1.3'
22
+ spec.add_development_dependency 'rake', '~> 10.3.2'
23
+ spec.add_development_dependency 'rspec', '~> 2.14'
24
24
 
25
- spec.add_dependency "timezone", "~> 0.3"
26
- spec.add_dependency "activesupport", "~> 4.0"
27
- spec.add_dependency 'nokogiri', "~> 1.6"
28
- spec.add_dependency 'geocoder', "~> 1.1"
29
- spec.add_dependency 'i18n', "~> 0.6"
25
+ spec.add_dependency 'timezone', '~> 0.3'
26
+ spec.add_dependency 'activesupport', '~> 4.0'
27
+ spec.add_dependency 'nokogiri', '~> 1.6'
28
+ spec.add_dependency 'geocoder', '~> 1.1'
29
+ spec.add_dependency 'i18n', '~> 0.6'
30
30
  end
@@ -3,7 +3,7 @@ module Fonecal
3
3
  attr_accessor :calendar
4
4
 
5
5
  def initialize(gps)
6
- self.calendar = File.new('f1cal.ical', 'w')
6
+ @calendar = File.new('fonecal.ics', 'w')
7
7
 
8
8
  @calendar.puts "BEGIN:VCALENDAR"
9
9
  @calendar.puts "VERSION:2.0"
@@ -27,7 +27,7 @@ module Fonecal
27
27
 
28
28
  @calendar.puts "SUMMARY:#{gp.grandPrix}: #{event.name}"
29
29
  @calendar.puts "DESCRIPTION:#{gp.raceTitle}: #{event.name}"
30
- @calendar.puts "DTSTAMP:#{Util.dtToUTC(DateTime.now)}Z"
30
+ @calendar.puts "DTSTAMP:#{Util.dtToUTC(Time.now)}Z"
31
31
  @calendar.puts "LOCATION:#{gp.city}, #{gp.country}"
32
32
  @calendar.puts "DTSTART:#{Util.dtToUTC(event.start)}Z"
33
33
  puts "#{gp.grandPrix}: #{event.name} starts #{event.start} UTC: #{event.start.utc}"
@@ -6,7 +6,7 @@ module Fonecal
6
6
  attr_accessor :site, :root
7
7
 
8
8
  def initialize(site)
9
- self.site = Nokogiri::HTML(open(site))
9
+ self.site = Nokogiri::HTML(open(site), nil, 'utf-8')
10
10
  self.root = Util.getRootUrl(site)
11
11
  end
12
12
  end
@@ -1,24 +1,35 @@
1
- require 'active_support/all'
1
+ require 'active_support/time'
2
2
 
3
3
  module Fonecal
4
4
  class Event
5
5
  attr_accessor :name, :start, :end
6
6
 
7
7
  def initialize(event, timezone)
8
- # UTC offset in hours, explicitely add +
9
- if (timezone.utc_offset / 60 / 60) > 0
10
- offset = "+#{timezone.utc_offset / 60 / 60}"
11
- else
12
- offset = offset.to_s
13
- end
14
-
15
8
  self.name = event[:type]
16
- self.start = DateTime.parse("#{event[:date]}T#{event[:start]} #{offset}")
17
9
 
18
- if event[:end]
19
- self.end = DateTime.parse("#{event[:date]}T#{event[:end]} #{offset}")
20
- else
21
- self.end = self.start + 4.hours
10
+ # Extract info from date string
11
+ date,month,year = event[:date].split(' ')[1..-1]
12
+
13
+ # Convert month from string to integer
14
+ month = Date::MONTHNAMES.index(month)
15
+
16
+ # Parse and set starting time
17
+ start_hr, start_m = event[:start].split(':')
18
+
19
+ # Set timezone to what was given
20
+ Time.zone = timezone.zone
21
+
22
+ # Look up timezone in day, taking dst into account
23
+ @start = Time.zone.local(year, month, date, start_hr, start_m, 0)
24
+
25
+ # Parse and set ending time
26
+ if event[:end] # a practice sessions
27
+ end_hr, end_m = event[:end].split(':')
28
+ @end = Time.zone.local(year, month, date, end_hr, end_m, 0)
29
+ elsif self.class == Qualifying
30
+ @end = @start + (1.hour + 30.minutes)
31
+ else # race
32
+ @end = @start + 4.hours
22
33
  end
23
34
  end
24
35
  end
@@ -23,8 +23,6 @@ module Fonecal
23
23
  else
24
24
  @res
25
25
  end
26
-
27
- #@location ||= Geocoder.search("#{@circuit.name}, #{@circuit.city}").first
28
26
  end
29
27
 
30
28
  def city
@@ -40,7 +38,11 @@ module Fonecal
40
38
  end
41
39
 
42
40
  def raceTitle
43
- @crawler.gp.gsub(/\w+/).map(&:capitalize).join(' ')
41
+ title = @crawler.gp.split(/(\W)/).map(&:capitalize).join
42
+
43
+ # Dirty decapitalization hack
44
+ title = title.gsub(/Í/, 'í')
45
+ title = title.gsub(/J/, 'j')
44
46
  end
45
47
 
46
48
  def grandPrix
@@ -53,14 +55,14 @@ module Fonecal
53
55
  def createEvents
54
56
  @crawler.timeTables.each do |day|
55
57
  day[:sessions].each do |event|
56
- type = event[:type]
58
+ type = event[:type]
57
59
  event[:date] = day[:date]
58
60
 
59
- if(type.include? "Practice")
61
+ if ['practice 1', 'practice 2', 'practice 3'].include?(type.downcase)
60
62
  @events << Practice.new(event, timezone)
61
- elsif(type.include? "Qualifying")
63
+ elsif type == "Qualifying"
62
64
  @events << Qualifying.new(event, timezone)
63
- elsif(type.include? "Race")
65
+ elsif type == "Race"
64
66
  @events << Race.new(event, timezone)
65
67
  end
66
68
  end
@@ -1,3 +1,3 @@
1
1
  module Fonecal
2
- VERSION = "0.1.0"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -0,0 +1,124 @@
1
+ require 'fonecal'
2
+
3
+ describe Fonecal::GrandPrix do
4
+
5
+ describe "Abu Dhabi GP" do
6
+ subject(:abudabiGP) { Fonecal::GrandPrix.new('http://www.formula1.com/races/in_detail/abu_dhabi_932/circuit_diagram.html') }
7
+
8
+ it "should have the correct race title" do
9
+ expect(abudabiGP.raceTitle).to eql "2014 Formula 1 Etihad Airways Abu Dhabi Grand Prix"
10
+ end
11
+
12
+ it "should be in Canada" do
13
+ expect(abudabiGP.country).to eql "United Arab Emirates"
14
+ end
15
+
16
+ it "should be in Montreal" do
17
+ expect(abudabiGP.city).to eql "Yas Marina"
18
+ end
19
+
20
+ it "should be in the EST timezone" do
21
+ gts = Timezone::Zone.new(zone: "Etc/GMT+4")
22
+ abuTS = Timezone::Zone.new(zone: "Asia/Dubai")
23
+ now = Time.now
24
+
25
+ expect(abudabiGP.timezone.time(now).to_i).to eq gts.time(now).to_i
26
+ expect(abudabiGP.timezone.time(now).to_i).to eq abuTS.time(now).to_i
27
+ end
28
+
29
+ it "should have 5 events" do
30
+ expect(abudabiGP.events.count).to eql 5
31
+ end
32
+
33
+ context "practice 1" do
34
+ subject(:p1) { abudabiGP.events.first }
35
+
36
+ it "should be of type Practice" do
37
+ expect(p1.class).to eql Fonecal::Practice
38
+ end
39
+
40
+ it "should start at 13:00 CET on friday" do
41
+ expect(p1.start).to eql Time.new(2014, 11, 21, 13, 0, 0, '+04:00')
42
+ puts p1.start.utc
43
+ expect(p1.start).to eql Time.new(2014, 11, 21, 10, 0, 0, '+01:00')
44
+ end
45
+
46
+ it "should end at 11:30 CET on friday" do
47
+ expect(p1.end).to eql Time.new(2014, 11, 21, 14, 30, 0, '+04:00')
48
+ expect(p1.end).to eql Time.new(2014, 11, 21, 11, 30, 0, '+01:00')
49
+ end
50
+ end
51
+
52
+ #context "practice 2" do
53
+ # subject(:p2) { abudabiGP.events[1] }
54
+
55
+ # it "should be of type Practice" do
56
+ # expect(p2.class).to eql Fonecal::Practice
57
+ # end
58
+
59
+ # it "should start at 20:00 on friday" do
60
+ # expect(p2.start).to eql Time.new(2014, 6, 6, 20, 0, 0, '+02:00')
61
+ # expect(p2.start).to eql Time.new(2014, 6, 6, 14, 0, 0, '+10:00')
62
+ # end
63
+
64
+ # it "should end at 21:30 on friday" do
65
+ # expect(p2.end).to eql Time.new(2014, 6, 6, 21, 30, 0, '+02:00')
66
+ # expect(p2.end).to eql Time.new(2014, 6, 6, 15, 30, 0, '+10:00')
67
+ # end
68
+ #end
69
+
70
+ #context "practice 3" do
71
+ # subject(:p3) { abudabiGP.events[2] }
72
+
73
+ # it "should be of type Practice" do
74
+ # expect(p3.class).to eql Fonecal::Practice
75
+ # end
76
+
77
+ # it "should start at 16:00 on saturday" do
78
+ # expect(p3.start).to eql Time.new(2014, 6, 7, 16, 0, 0, '+02:00')
79
+ # expect(p3.start).to eql Time.new(2014, 6, 7, 10, 0, 0, '+10:00')
80
+ # end
81
+
82
+ # it "should end at 17:00 on saturday" do
83
+ # expect(p3.end).to eql Time.new(2014, 6, 7, 17, 0, 0, '+02:00')
84
+ # expect(p3.end).to eql Time.new(2014, 6, 7, 11, 0, 0, '+10:00')
85
+ # end
86
+ #end
87
+
88
+ #context "qualifying" do
89
+ # subject(:q) { abudabiGP.events[3] }
90
+
91
+ # it "should be of type Practice" do
92
+ # expect(q.class).to eql Fonecal::Qualifying
93
+ # end
94
+
95
+ # it "should start at 19:00 on saturday" do
96
+ # expect(q.start).to eql Time.new(2014, 6, 7, 19, 0, 0, '+02:00')
97
+ # expect(q.start).to eql Time.new(2014, 6, 7, 13, 0, 0, '+10:00')
98
+ # end
99
+
100
+ # it "should end at 20:30 on saturday" do
101
+ # expect(q.end).to eql Time.new(2014, 6, 7, 20, 30, 0, '+02:00')
102
+ # expect(q.end).to eql Time.new(2014, 6, 7, 14, 30, 0, '+10:00')
103
+ # end
104
+ #end
105
+
106
+ #context "race" do
107
+ # subject(:race) { abudabiGP.events[4] }
108
+
109
+ # it "should be of type Practice" do
110
+ # expect(race.class).to eql Fonecal::Race
111
+ # end
112
+
113
+ # it "should start at 20:00 on sunday" do
114
+ # expect(race.start).to eql Time.new(2014, 6, 8, 20, 0, 0, '+02:00')
115
+ # expect(race.start).to eql Time.new(2014, 6, 8, 14, 0, 0, '+10:00')
116
+ # end
117
+
118
+ # it "should end at 24:00 on sunday" do
119
+ # expect(race.end).to eql Time.new(2014, 6, 8, 24, 0, 0, '+02:00')
120
+ # expect(race.end).to eql Time.new(2014, 6, 8, 18, 0, 0, '+10:00')
121
+ # end
122
+ #end
123
+ end
124
+ end
@@ -0,0 +1,123 @@
1
+ require 'fonecal'
2
+
3
+ describe Fonecal::GrandPrix do
4
+
5
+ describe "Australian GP" do
6
+ subject(:australianGP) { Fonecal::GrandPrix.new('http://www.formula1.com/races/in_detail/australia_914/circuit_diagram.html') }
7
+
8
+ it "should have the correct race title" do
9
+ expect(australianGP.raceTitle).to eql "2014 Formula 1 Rolex Australian Grand Prix"
10
+ end
11
+
12
+ it "should be in Canada" do
13
+ expect(australianGP.country).to eql "Australia"
14
+ end
15
+
16
+ it "should be in Montreal" do
17
+ expect(australianGP.city).to eql "Melbourne"
18
+ end
19
+
20
+ it "should be in the EST timezone" do
21
+ aestTS = Timezone::Zone.new(zone: "Etc/GMT+10")
22
+ melbourneTS = Timezone::Zone.new(zone: "Australia/Melbourne")
23
+ now = Time.now
24
+
25
+ #expect(australianGP.timezone.time(now).to_i).to eq estTS.time(now).to_i
26
+ expect(australianGP.timezone.time(now).to_i).to eq melbourneTS.time(now).to_i
27
+ end
28
+
29
+ it "should have 5 events" do
30
+ expect(australianGP.events.count).to eql 5
31
+ end
32
+
33
+ context "practice 1" do
34
+ subject(:p1) { australianGP.events.first }
35
+
36
+ it "should be of type Practice" do
37
+ expect(p1.class).to eql Fonecal::Practice
38
+ end
39
+
40
+ it "should start at 2:30 CET on friday" do
41
+ expect(p1.start).to eql Time.new(2014, 3, 14, 12, 30, 0, '+10:00')
42
+ expect(p1.start).to eql Time.new(2014, 3, 14, 2, 30, 0, '+01:00')
43
+ end
44
+
45
+ it "should end at 4:30 CET on friday" do
46
+ expect(p1.end).to eql Time.new(2014, 3, 14, 14, 0, 0, '+10:00')
47
+ expect(p1.end).to eql Time.new(2014, 3, 14, 4, 0, 0, '+01:00')
48
+ end
49
+ end
50
+
51
+ #context "practice 2" do
52
+ # subject(:p2) { australianGP.events[1] }
53
+
54
+ # it "should be of type Practice" do
55
+ # expect(p2.class).to eql Fonecal::Practice
56
+ # end
57
+
58
+ # it "should start at 20:00 on friday" do
59
+ # expect(p2.start).to eql Time.new(2014, 6, 6, 20, 0, 0, '+02:00')
60
+ # expect(p2.start).to eql Time.new(2014, 6, 6, 14, 0, 0, '+10:00')
61
+ # end
62
+
63
+ # it "should end at 21:30 on friday" do
64
+ # expect(p2.end).to eql Time.new(2014, 6, 6, 21, 30, 0, '+02:00')
65
+ # expect(p2.end).to eql Time.new(2014, 6, 6, 15, 30, 0, '+10:00')
66
+ # end
67
+ #end
68
+
69
+ #context "practice 3" do
70
+ # subject(:p3) { australianGP.events[2] }
71
+
72
+ # it "should be of type Practice" do
73
+ # expect(p3.class).to eql Fonecal::Practice
74
+ # end
75
+
76
+ # it "should start at 16:00 on saturday" do
77
+ # expect(p3.start).to eql Time.new(2014, 6, 7, 16, 0, 0, '+02:00')
78
+ # expect(p3.start).to eql Time.new(2014, 6, 7, 10, 0, 0, '+10:00')
79
+ # end
80
+
81
+ # it "should end at 17:00 on saturday" do
82
+ # expect(p3.end).to eql Time.new(2014, 6, 7, 17, 0, 0, '+02:00')
83
+ # expect(p3.end).to eql Time.new(2014, 6, 7, 11, 0, 0, '+10:00')
84
+ # end
85
+ #end
86
+
87
+ #context "qualifying" do
88
+ # subject(:q) { australianGP.events[3] }
89
+
90
+ # it "should be of type Practice" do
91
+ # expect(q.class).to eql Fonecal::Qualifying
92
+ # end
93
+
94
+ # it "should start at 19:00 on saturday" do
95
+ # expect(q.start).to eql Time.new(2014, 6, 7, 19, 0, 0, '+02:00')
96
+ # expect(q.start).to eql Time.new(2014, 6, 7, 13, 0, 0, '+10:00')
97
+ # end
98
+
99
+ # it "should end at 20:30 on saturday" do
100
+ # expect(q.end).to eql Time.new(2014, 6, 7, 20, 30, 0, '+02:00')
101
+ # expect(q.end).to eql Time.new(2014, 6, 7, 14, 30, 0, '+10:00')
102
+ # end
103
+ #end
104
+
105
+ #context "race" do
106
+ # subject(:race) { australianGP.events[4] }
107
+
108
+ # it "should be of type Practice" do
109
+ # expect(race.class).to eql Fonecal::Race
110
+ # end
111
+
112
+ # it "should start at 20:00 on sunday" do
113
+ # expect(race.start).to eql Time.new(2014, 6, 8, 20, 0, 0, '+02:00')
114
+ # expect(race.start).to eql Time.new(2014, 6, 8, 14, 0, 0, '+10:00')
115
+ # end
116
+
117
+ # it "should end at 24:00 on sunday" do
118
+ # expect(race.end).to eql Time.new(2014, 6, 8, 24, 0, 0, '+02:00')
119
+ # expect(race.end).to eql Time.new(2014, 6, 8, 18, 0, 0, '+10:00')
120
+ # end
121
+ #end
122
+ end
123
+ end