gares 1.1.1 → 2.0.0.pre.pre
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 +4 -4
- data/Guardfile +1 -1
- data/README.md +8 -6
- data/gares.gemspec +1 -0
- data/lib/gares/base.rb +70 -44
- data/lib/gares/errors.rb +14 -0
- data/lib/gares/sales.rb +1 -2
- data/lib/gares/search.rb +36 -14
- data/lib/gares/services.rb +2 -2
- data/lib/gares/station_list.rb +1 -3
- data/lib/gares/train.rb +28 -3
- data/lib/gares/train_stop.rb +15 -2
- data/lib/gares/version.rb +1 -1
- data/lib/gares.rb +2 -0
- data/spec/fixtures/get-train-12345 +219 -0
- data/spec/fixtures/get-train-6815 +6 -11
- data/spec/fixtures/get-train-6815-0 +0 -0
- data/spec/fixtures/get-train-6815-0-data +627 -0
- data/spec/fixtures/get-train-6815-1 +0 -0
- data/spec/fixtures/get-train-6815-1-data +367 -0
- data/spec/fixtures/post-train-12345 +0 -0
- data/spec/fixtures/post-train-6815 +0 -0
- data/spec/fixtures/stations.csv +21484 -0
- data/spec/gares/sales_spec.rb +3 -1
- data/spec/gares/search_spec.rb +105 -40
- data/spec/gares/station_spec.rb +64 -0
- data/spec/gares/train_spec.rb +50 -9
- data/spec/spec_helper.rb +15 -2
- data/tasks/fixtures.rake +18 -0
- metadata +27 -5
- data/spec/gares/gare_spec.rb +0 -82
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f87e7dc8b8d185548c8dcc4c12c789e07802caea
|
4
|
+
data.tar.gz: 971aa5a58e033f79d41f901899bc6d862c56f5f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4432ec3fa4011d82f5b22f63aa647e7b75fca52fa2222335032f9cbb0b5078bcb59008d9d9bfd4fe9474143248d212beac197c2c5758b871519968bed5a8fd38
|
7
|
+
data.tar.gz: 9afd2bd055b35a12e10b15b10d9a29c4208744c0ae1a119c39403f4b8ccfb9ad06c66e1f6d92c8b6bdd09113e6d9c9a068ee9b41412cbad0586127a4ced2f589
|
data/Guardfile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
group 'gem' do
|
2
2
|
guard 'rspec', :cmd => "bundle exec rspec", :all_on_start => false, :all_after_pass => false, :failed_mode => :focus do
|
3
3
|
watch(%r{^spec/.+_spec\.rb$})
|
4
|
-
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/gares/#{m[1]}_spec.rb" }
|
4
|
+
watch(%r{^lib/gares/(.+)\.rb$}) { |m| "spec/gares/#{m[1]}_spec.rb" }
|
5
5
|
end
|
6
6
|
end
|
data/README.md
CHANGED
@@ -22,7 +22,7 @@ Gares currently features the following:
|
|
22
22
|
g = Gares::Station.new("frlpd")
|
23
23
|
|
24
24
|
g.name
|
25
|
-
#=> "Lyon Part
|
25
|
+
#=> "Lyon Part-Dieu"
|
26
26
|
|
27
27
|
g.wifi?
|
28
28
|
#=> true
|
@@ -33,7 +33,7 @@ Gares currently features the following:
|
|
33
33
|
g.services.first
|
34
34
|
#=> "Services à la clientèle"
|
35
35
|
|
36
|
-
[g.
|
36
|
+
[g.latitude, g.longitude]
|
37
37
|
#=> [45.760281, 4.859801]
|
38
38
|
|
39
39
|
See the [`Gares::Base` class documentation](http://www.rubydoc.info/github/paulrbr/gares/master/Gares/Base) for all available data on a station.
|
@@ -43,7 +43,7 @@ See the [`Gares::Base` class documentation](http://www.rubydoc.info/github/paulr
|
|
43
43
|
g = Gares::Search.new("Aix")
|
44
44
|
|
45
45
|
g.stations.size
|
46
|
-
#=>
|
46
|
+
#=> 28
|
47
47
|
|
48
48
|
# or
|
49
49
|
|
@@ -51,14 +51,14 @@ See the [`Gares::Base` class documentation](http://www.rubydoc.info/github/paulr
|
|
51
51
|
station = stations.last
|
52
52
|
|
53
53
|
station.name
|
54
|
-
#=> "
|
54
|
+
#=> "Aéroport-Lyon-Saint-Exupéry"
|
55
55
|
|
56
56
|
### Train information:
|
57
57
|
|
58
58
|
train = Gares::Train.new(11641, Time.now)
|
59
59
|
|
60
60
|
train.departure.station
|
61
|
-
#=> #<Gares::Station:0x000f0000000000 @
|
61
|
+
#=> #<Gares::Station:0x000f0000000000 @name="Paris-Gare-de-l’Est", ...>
|
62
62
|
|
63
63
|
train.departure.departure_date
|
64
64
|
#=> 2015-04-25 06:42:00 +0200
|
@@ -70,7 +70,7 @@ See the [`Gares::Base` class documentation](http://www.rubydoc.info/github/paulr
|
|
70
70
|
#=> false
|
71
71
|
|
72
72
|
train.arrival.station.name
|
73
|
-
#=> "Culmont
|
73
|
+
#=> "Culmont-Chalindrey"
|
74
74
|
|
75
75
|
train.arrival.platform
|
76
76
|
#=> "B"
|
@@ -132,3 +132,5 @@ _This gem is not endorsed or affiliated with gares-en-mouvement.com, nor SNCF, I
|
|
132
132
|
## License
|
133
133
|
|
134
134
|
See [MIT-LICENSE](https://github.com/paulrbr/gares/blob/master/MIT-LICENSE)
|
135
|
+
|
136
|
+
Station database [ODbL LICENSE](https://raw.githubusercontent.com/capitainetrain/stations/master/LICENCE.txt)
|
data/gares.gemspec
CHANGED
data/lib/gares/base.rb
CHANGED
@@ -1,92 +1,118 @@
|
|
1
1
|
module Gares
|
2
2
|
# Represents something on gare-en-mouvement.com
|
3
|
-
class Base
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
3
|
+
class Base < Hashie::Dash
|
4
|
+
property :id
|
5
|
+
property :name
|
6
|
+
property :slug
|
7
|
+
property :sncf_id
|
8
|
+
property :longitude
|
9
|
+
property :latitude
|
10
|
+
property :uic
|
11
|
+
property :uic8_sncf
|
12
|
+
property :parent_station_id
|
13
|
+
property :is_city
|
14
|
+
property :country
|
15
|
+
property :is_main_station
|
16
|
+
property :time_zone
|
17
|
+
property :is_suggestable
|
18
|
+
property :sncf_is_enabled
|
19
|
+
property :idtgv_id
|
20
|
+
property :idtgv_is_enabled
|
21
|
+
property :db_id
|
22
|
+
property :db_is_enabled
|
23
|
+
property :idbus_id
|
24
|
+
property :idbus_is_enabled
|
25
|
+
property :ouigo_id
|
26
|
+
property :ouigo_is_enabled
|
27
|
+
property :trenitalia_id
|
28
|
+
property :trenitalia_is_enabled
|
29
|
+
property :ntv_id
|
30
|
+
property :ntv_is_enabled
|
31
|
+
property :'info:fr'
|
32
|
+
property :'info:en'
|
33
|
+
property :'info:de'
|
34
|
+
property :'info:it'
|
35
|
+
property :same_as
|
36
|
+
|
37
|
+
# @deprecated
|
30
38
|
def services
|
31
|
-
|
39
|
+
warn "[DEPRECATION] since gares-en-mouvement.com does not exist anymore."
|
40
|
+
@services ||= Services.new(sncf_id: sncf_id)
|
32
41
|
@services.all
|
33
42
|
end
|
34
43
|
|
44
|
+
# @deprecated
|
35
45
|
def sales
|
36
|
-
|
46
|
+
warn "[DEPRECATION] since gares-en-mouvement.com does not exist anymore."
|
47
|
+
@sales ||= Sales.new(sncf_id: sncf_id)
|
37
48
|
@sales.all
|
38
49
|
end
|
39
50
|
|
51
|
+
# @deprecated
|
40
52
|
def horaires
|
53
|
+
warn "[DEPRECATION] since gares-en-mouvement.com does not exist anymore."
|
41
54
|
document.search('ul.ouverture_heure li').
|
42
55
|
map { |horaire| horaire.inner_html } rescue []
|
43
56
|
end
|
44
57
|
alias opening_hours horaires
|
45
58
|
|
46
59
|
# Whether the gare has a defibrillator or not
|
60
|
+
# @deprecated
|
47
61
|
def defibrillateur?
|
62
|
+
warn "[DEPRECATION] since gares-en-mouvement.com does not exist anymore."
|
48
63
|
!document.at('div.defibrillateur').nil?
|
49
64
|
end
|
50
65
|
alias defibrillator? defibrillateur?
|
51
66
|
|
52
67
|
# Whether the gare is equipped with wifi or not
|
68
|
+
# @deprecated
|
53
69
|
def wifi?
|
70
|
+
warn "[DEPRECATION] since gares-en-mouvement.com does not exist anymore."
|
54
71
|
!document.at('div.wifi').nil?
|
55
72
|
end
|
56
73
|
|
74
|
+
# @deprecated
|
57
75
|
def has_borne?
|
76
|
+
warn "[DEPRECATION] since gares-en-mouvement.com does not exist anymore."
|
58
77
|
sales.any? { |sales_service| sales_service =~ /bornes?.libre.service/i }
|
59
78
|
end
|
60
79
|
|
61
|
-
#
|
62
|
-
def
|
63
|
-
|
64
|
-
@name
|
65
|
-
else
|
66
|
-
@name = document.at('h1').inner_html.gsub(NAME, '') rescue nil
|
67
|
-
end
|
80
|
+
# deprecated
|
81
|
+
def slug
|
82
|
+
sncf_id.downcase
|
68
83
|
end
|
69
84
|
|
70
|
-
|
85
|
+
# deprecated
|
86
|
+
def lat
|
87
|
+
latitude
|
88
|
+
end
|
71
89
|
|
72
|
-
|
73
|
-
|
74
|
-
|
90
|
+
# deprecated
|
91
|
+
def long
|
92
|
+
longitude
|
75
93
|
end
|
76
94
|
|
95
|
+
private
|
96
|
+
|
77
97
|
# Returns a new Nokogiri document for parsing.
|
78
98
|
def document
|
79
|
-
@document ||= Nokogiri::HTML(
|
99
|
+
@document ||= Nokogiri::HTML(self.class.external_data(sncf_id))
|
80
100
|
end
|
81
101
|
|
82
102
|
# Use HTTParty to fetch the raw HTML for this gare.
|
83
|
-
|
84
|
-
|
103
|
+
# @deprecated
|
104
|
+
def self.external_data(sncf_id, page = :"votre-gare")
|
105
|
+
open("http://www.gares-en-mouvement.com/fr/#{sncf_id.downcase}/#{page}")
|
85
106
|
end
|
86
107
|
|
87
|
-
# Convenience method for search
|
108
|
+
# Convenience method for search (by name)
|
88
109
|
def self.search(query)
|
89
110
|
Gares::Search.new(query).stations
|
90
111
|
end
|
112
|
+
|
113
|
+
# Convenience method for search_by_sncf_id
|
114
|
+
def self.search_by_sncf_id(query)
|
115
|
+
Gares::Search.new(query, :sncf_id).stations
|
116
|
+
end
|
91
117
|
end # Base
|
92
118
|
end # Gares
|
data/lib/gares/errors.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module Gares
|
2
|
+
# All errors from this gem will inherit from this one.
|
3
|
+
class Error < StandardError
|
4
|
+
end
|
5
|
+
class UnsupportedIndex < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
# Raised when requesting a train that does not exist.
|
9
|
+
class TrainNotFound < Error
|
10
|
+
end
|
11
|
+
# Raised when requesting a station that does not exist.
|
12
|
+
class StationNotFound < Error
|
13
|
+
end
|
14
|
+
end
|
data/lib/gares/sales.rb
CHANGED
data/lib/gares/search.rb
CHANGED
@@ -3,11 +3,11 @@ module Gares
|
|
3
3
|
class Search < StationList
|
4
4
|
attr_reader :query
|
5
5
|
|
6
|
-
# This is
|
7
|
-
GARES_LIST_URL = "https://
|
6
|
+
# This is the stations database from capitainetrain.com
|
7
|
+
GARES_LIST_URL = "https://raw.githubusercontent.com/capitainetrain/stations/master/stations.csv"
|
8
8
|
|
9
9
|
# List of keywords to ignore while searching
|
10
|
-
IGNORE_KEYWORDS = ["ST"]
|
10
|
+
IGNORE_KEYWORDS = ["ST", "SAINT", "GARE", "SNCF"]
|
11
11
|
# Initialize a new Station search with the specified query
|
12
12
|
#
|
13
13
|
# search = Gares::Search.new("Aix")
|
@@ -15,8 +15,12 @@ module Gares
|
|
15
15
|
# Gares::Search is lazy loaded, meaning that unless you access the +stations+
|
16
16
|
# attribute, no remomte query is made.
|
17
17
|
#
|
18
|
-
|
18
|
+
# Search can by done via the :name or :sncf_id field given in parameter.
|
19
|
+
# Defaults to the :name field.
|
20
|
+
def initialize(query, field = :name)
|
21
|
+
fail UnsupportedIndex unless %w(name sncf_id).include?(field.to_s)
|
19
22
|
@query = query
|
23
|
+
@by = field
|
20
24
|
end
|
21
25
|
|
22
26
|
# Returns an array of Gares::Station objects in order to easily search result yielded.
|
@@ -27,24 +31,42 @@ module Gares
|
|
27
31
|
|
28
32
|
private
|
29
33
|
|
30
|
-
def
|
31
|
-
@
|
34
|
+
def result
|
35
|
+
@raw_result ||= case @by
|
36
|
+
when :name
|
37
|
+
keywords = @query.to_ascii.split(/[ -]/).select { |keyword| !IGNORE_KEYWORDS.include?(keyword.upcase) }
|
38
|
+
regexp_query = keywords.join(".*")
|
39
|
+
self.class.data(@by).select do |index, v|
|
40
|
+
index && index =~ /#{regexp_query}/i
|
41
|
+
end
|
42
|
+
when :sncf_id
|
43
|
+
{ @query.downcase => self.class.data(@by)[@query.downcase] }
|
44
|
+
end
|
45
|
+
|
46
|
+
@result ||= @raw_result.map { |_, raw_station| Gares::Station.new(raw_station) }
|
32
47
|
end
|
33
48
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
49
|
+
# Read stations.csv file into memory
|
50
|
+
# @param index either :name or :sncf_id
|
51
|
+
# @return [Hash<String, Hash>] list of stations indexed in a Hash
|
52
|
+
def self.data(index)
|
53
|
+
@@raw_data ||= SmarterCSV.process(open(GARES_LIST_URL), col_sep: ";")
|
54
|
+
case index
|
55
|
+
when :name
|
56
|
+
@@data_by_name ||= index_data(@@raw_data, index)
|
57
|
+
when :sncf_id
|
58
|
+
@@data_by_sncf_id ||= index_data(@@raw_data, index)
|
38
59
|
end
|
39
60
|
end
|
40
61
|
|
41
|
-
def self.
|
42
|
-
|
62
|
+
def self.index_data(data, by)
|
63
|
+
data.map do |raw_station|
|
64
|
+
[raw_station[by].to_ascii.downcase, raw_station] if raw_station[by] && raw_station[:uic]
|
65
|
+
end.compact.to_h
|
43
66
|
end
|
44
67
|
|
45
68
|
def parse_station
|
46
|
-
|
47
|
-
[Gares::Station.new(station.slug, station.name)]
|
69
|
+
[result.first]
|
48
70
|
end
|
49
71
|
|
50
72
|
def exact_match?
|
data/lib/gares/services.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
module Gares
|
2
|
+
# @deprecated
|
2
3
|
class Services < Base
|
3
4
|
|
4
5
|
def all
|
@@ -9,8 +10,7 @@ module Gares
|
|
9
10
|
private
|
10
11
|
|
11
12
|
def document
|
12
|
-
@document ||= Nokogiri::HTML(
|
13
|
-
@slug, :"services-en-gare/service/"))
|
13
|
+
@document ||= Nokogiri::HTML(self.class.external_data(sncf_id, :"services-en-gare/service/"))
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
data/lib/gares/station_list.rb
CHANGED
data/lib/gares/train.rb
CHANGED
@@ -42,19 +42,44 @@ module Gares
|
|
42
42
|
|
43
43
|
private
|
44
44
|
|
45
|
+
def itinerary_available?
|
46
|
+
document.css('ul.itinerary-details').size > 0
|
47
|
+
end
|
48
|
+
|
45
49
|
# Returns a new Nokogiri document for parsing.
|
46
50
|
def document
|
47
|
-
|
51
|
+
if !@document
|
52
|
+
@document = Nokogiri::HTML(self.class.request_sncf(@number, @date))
|
53
|
+
if !itinerary_available?
|
54
|
+
@document = Nokogiri::HTML(self.class.request_sncf_itinerary(0))
|
55
|
+
end
|
56
|
+
end
|
57
|
+
if @document.at('#no_results')
|
58
|
+
fail TrainNotFound, @document.at('#no_results b').inner_html
|
59
|
+
end
|
60
|
+
@document
|
48
61
|
end
|
49
62
|
|
50
63
|
def self.request_sncf(number, date)
|
51
64
|
uri = URI.parse("http://www.sncf.com/sncf/train")
|
52
65
|
response = Net::HTTP.post_form(uri, {"numeroTrain" => number, "date" => date.strftime("%d/%m/%Y")})
|
53
|
-
cookies = response.get_fields('Set-Cookie').map { |cookie| cookie.split(";").first }.join(";")
|
66
|
+
@cookies = response.get_fields('Set-Cookie').map { |cookie| cookie.split(";").first }.join(";")
|
54
67
|
|
55
68
|
uri = URI.parse("http://www.sncf.com/en/horaires-info-trafic/train/resultats")
|
56
69
|
req = Net::HTTP::Get.new(uri.path)
|
57
|
-
req.add_field("Cookie", cookies)
|
70
|
+
req.add_field("Cookie", @cookies)
|
71
|
+
Net::HTTP.new(uri.host, uri.port).start { |http| http.request(req) }.body
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.request_sncf_itinerary(index)
|
75
|
+
uri = URI.parse("http://www.sncf.com/sncf/train/displayDetailTrain?idItineraire=#{index}")
|
76
|
+
req = Net::HTTP::Get.new(uri)
|
77
|
+
req.add_field("Cookie", @cookies) if @cookies
|
78
|
+
Net::HTTP.new(uri.host, uri.port).start { |http| http.request(req) }.body
|
79
|
+
|
80
|
+
uri = URI.parse("http://www.sncf.com/en/horaires-info-trafic/train/resultats?#{index}")
|
81
|
+
req = Net::HTTP::Get.new(uri)
|
82
|
+
req.add_field("Cookie", @cookies) if @cookies
|
58
83
|
Net::HTTP.new(uri.host, uri.port).start { |http| http.request(req) }.body
|
59
84
|
end
|
60
85
|
|
data/lib/gares/train_stop.rb
CHANGED
@@ -74,9 +74,22 @@ module Gares
|
|
74
74
|
raw_name = node.at('td.stations div.station').inner_html.strip
|
75
75
|
stations = Station.search(raw_name)
|
76
76
|
@station = if stations.size > 1
|
77
|
+
raw_name.gsub!(/[ -]/, '.*')
|
78
|
+
exact_match = /^#{raw_name}$/i
|
79
|
+
begin_match = /^#{raw_name}/i
|
80
|
+
end_match = /#{raw_name}$/
|
81
|
+
middle_match = /#{raw_name}/i
|
77
82
|
stations.find do |station|
|
78
|
-
name
|
79
|
-
|
83
|
+
station.name.to_ascii.match(exact_match)
|
84
|
+
end ||
|
85
|
+
stations.find do |station|
|
86
|
+
station.name.to_ascii.match(begin_match)
|
87
|
+
end ||
|
88
|
+
stations.find do |station|
|
89
|
+
station.name.to_ascii.match(end_match)
|
90
|
+
end ||
|
91
|
+
stations.find do |station|
|
92
|
+
station.name.to_ascii.match(middle_match)
|
80
93
|
end
|
81
94
|
else
|
82
95
|
stations.first
|
data/lib/gares/version.rb
CHANGED
data/lib/gares.rb
CHANGED
@@ -6,9 +6,11 @@ require 'rubygems'
|
|
6
6
|
require 'nokogiri'
|
7
7
|
require 'json'
|
8
8
|
require 'hashie'
|
9
|
+
require 'smarter_csv'
|
9
10
|
require 'unidecoder'
|
10
11
|
require 'httparty'
|
11
12
|
|
13
|
+
require 'gares/errors'
|
12
14
|
require 'gares/base'
|
13
15
|
require 'gares/station'
|
14
16
|
require 'gares/station_list'
|