gares 2.0.0.pre.pre → 2.0.0.pre.1

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: f87e7dc8b8d185548c8dcc4c12c789e07802caea
4
- data.tar.gz: 971aa5a58e033f79d41f901899bc6d862c56f5f0
3
+ metadata.gz: a3462299801d297e26ac19012e511cb92b71257b
4
+ data.tar.gz: 2402a19990a9bf1f1e1b8334b24126a08c368439
5
5
  SHA512:
6
- metadata.gz: 4432ec3fa4011d82f5b22f63aa647e7b75fca52fa2222335032f9cbb0b5078bcb59008d9d9bfd4fe9474143248d212beac197c2c5758b871519968bed5a8fd38
7
- data.tar.gz: 9afd2bd055b35a12e10b15b10d9a29c4208744c0ae1a119c39403f4b8ccfb9ad06c66e1f6d92c8b6bdd09113e6d9c9a068ee9b41412cbad0586127a4ced2f589
6
+ metadata.gz: 79d40ec3a9d068bd76716cf73e1de3c45f4ea439663fbfeb2cee2588ca8c4fc428652db6f52ed4532d91bfbbbf5cbbd85ba888b848d91d0e6001539f2817cee1
7
+ data.tar.gz: dbfd7ea33abbb67f5334f81834ef8d9d652d9ef232acf3e36ce94bd6feed2265b69860cf26a7b6f8a9bf1babba29d3e5344c5c1ad8d683e2f2b7033d6239a664
data/gares.gemspec CHANGED
@@ -24,6 +24,7 @@ Gem::Specification.new do |s|
24
24
  s.add_dependency 'smarter_csv', '~> 1.0'
25
25
  s.add_dependency 'unidecoder', '~> 1.1'
26
26
  s.add_dependency 'httparty', '~> 0.13'
27
+ s.add_dependency 'trie'
27
28
 
28
29
  s.add_development_dependency 'rake'
29
30
  s.add_development_dependency 'rspec'
@@ -0,0 +1,47 @@
1
+ # Fork of https://raw.githubusercontent.com/rails/rails/master/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
2
+ class Module
3
+ def mattr_reader(*syms)
4
+ syms.each do |sym|
5
+ raise NameError.new("invalid attribute name: #{sym}") unless sym =~ /^[_A-Za-z]\w*$/
6
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
7
+ @@#{sym} = nil unless defined? @@#{sym}
8
+
9
+ def self.#{sym}
10
+ @@#{sym}
11
+ end
12
+ EOS
13
+
14
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
15
+ def #{sym}
16
+ @@#{sym}
17
+ end
18
+ EOS
19
+ class_variable_set("@@#{sym}", yield) if block_given?
20
+ end
21
+ end
22
+
23
+ def mattr_writer(*syms)
24
+ syms.each do |sym|
25
+ raise NameError.new("invalid attribute name: #{sym}") unless sym =~ /^[_A-Za-z]\w*$/
26
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
27
+ @@#{sym} = nil unless defined? @@#{sym}
28
+
29
+ def self.#{sym}=(obj)
30
+ @@#{sym} = obj
31
+ end
32
+ EOS
33
+
34
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
35
+ def #{sym}=(obj)
36
+ @@#{sym} = obj
37
+ end
38
+ EOS
39
+ send("#{sym}=", yield) if block_given?
40
+ end
41
+ end
42
+
43
+ def mattr_accessor(*syms, &blk)
44
+ mattr_reader(*syms, &blk)
45
+ mattr_writer(*syms, &blk)
46
+ end
47
+ end
data/lib/gares/search.rb CHANGED
@@ -1,13 +1,16 @@
1
+ require 'trie'
2
+
1
3
  module Gares
2
4
  # Search Gares-en-mouvement for a station name
3
5
  class Search < StationList
6
+ @@trie = nil
7
+ mattr_reader :trie
8
+
4
9
  attr_reader :query
5
10
 
6
11
  # This is the stations database from capitainetrain.com
7
12
  GARES_LIST_URL = "https://raw.githubusercontent.com/capitainetrain/stations/master/stations.csv"
8
13
 
9
- # List of keywords to ignore while searching
10
- IGNORE_KEYWORDS = ["ST", "SAINT", "GARE", "SNCF"]
11
14
  # Initialize a new Station search with the specified query
12
15
  #
13
16
  # search = Gares::Search.new("Aix")
@@ -29,41 +32,46 @@ module Gares
29
32
  @stations ||= (exact_match? ? parse_station : parse_stations)
30
33
  end
31
34
 
35
+ def self.find(str)
36
+ trie.find_prefix(str)
37
+ end
38
+
32
39
  private
33
40
 
34
41
  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] }
42
+ query = self.class.simplify(@query)
43
+ if @raw_results.nil?
44
+ @raw_results = self.class.find(query).values
45
+ # try first keyword if nothing found
46
+ @raw_results = @raw_results.empty? ? self.class.find(query.split(" ").first).values : @raw_results
44
47
  end
45
-
46
- @result ||= @raw_result.map { |_, raw_station| Gares::Station.new(raw_station) }
48
+ @result ||= @raw_results.map { |raw_station| Gares::Station.new(raw_station) }
47
49
  end
48
50
 
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)
59
- end
51
+ def self.simplify(str)
52
+ str.to_ascii.downcase
53
+ .gsub(/\bsaint\b/, "st")
54
+ .gsub(/[^a-z]/, " ")
55
+ .gsub(/\s+/, " ")
56
+ .strip
60
57
  end
61
58
 
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
59
+ # Read stations.csv file into memory into a Trie data structure
60
+ def self.load_data
61
+ if @@trie.nil?
62
+ raw_data ||= SmarterCSV.process(open(GARES_LIST_URL), col_sep: ";")
63
+ trie = Trie.new
64
+
65
+ raw_data.each do |raw_station|
66
+ next if raw_station[:name].nil? || raw_station[:sncf_id].nil? || raw_station[:uic].nil?
67
+ trie.insert(simplify(raw_station[:name]), raw_station)
68
+ trie.insert(simplify(raw_station[:sncf_id]), raw_station)
69
+ end
70
+
71
+ @@trie = trie
72
+ end
66
73
  end
74
+ load_data
67
75
 
68
76
  def parse_station
69
77
  [result.first]
data/lib/gares/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Gares
2
- VERSION = '2.0.0-pre'
2
+ VERSION = '2.0.0-1'
3
3
  end
data/lib/gares.rb CHANGED
@@ -9,6 +9,8 @@ require 'hashie'
9
9
  require 'smarter_csv'
10
10
  require 'unidecoder'
11
11
  require 'httparty'
12
+ require 'attribute_accessors'
13
+ require 'string_extensions'
12
14
 
13
15
  require 'gares/errors'
14
16
  require 'gares/base'
@@ -17,7 +19,6 @@ require 'gares/station_list'
17
19
  require 'gares/sales'
18
20
  require 'gares/services'
19
21
  require 'gares/search'
20
- require 'gares/string_extensions'
21
22
  require 'gares/train'
22
23
  require 'gares/train_stop'
23
24
  require 'gares/version'
@@ -0,0 +1,20 @@
1
+ require 'cgi'
2
+
3
+ module StringExtensions
4
+ # Unescape HTML
5
+ def unescape_html
6
+ CGI.unescapeHTML(encode('UTF-8'))
7
+ end
8
+
9
+ # Strip tags
10
+ def strip_tags
11
+ gsub(/<\/?[^>]*>/, '')
12
+ end
13
+
14
+ # Strips out whitespace then tests if the string is empty.
15
+ def blank?
16
+ strip.empty?
17
+ end unless method_defined?(:blank?)
18
+ end
19
+
20
+ String.send :include, StringExtensions
@@ -4,15 +4,15 @@ describe Gares::Search do
4
4
  describe "search by station name" do
5
5
  context 'with multiple search results' do
6
6
  subject do
7
- Gares::Search.new('étienne')
7
+ Gares::Search.new('saint étienne')
8
8
  end
9
9
 
10
10
  it 'should remember the query' do
11
- expect(subject.query).to eql('étienne')
11
+ expect(subject.query).to eql('saint étienne')
12
12
  end
13
13
 
14
- it 'should find 28 results' do
15
- expect(subject.stations.size).to eql(12)
14
+ it 'should find 11 results' do
15
+ expect(subject.stations.size).to eql(11)
16
16
  end
17
17
 
18
18
  it 'should return Gares::Station objects only' do
@@ -32,7 +32,7 @@ describe Gares::Search do
32
32
  subject { Gares::Station.search('Saone').first }
33
33
 
34
34
  it 'should give the proper name' do
35
- expect(subject.name).to eql('Port-sur-Saône')
35
+ expect(subject.name).to eql('Saône')
36
36
  end
37
37
  end
38
38
 
@@ -82,7 +82,7 @@ describe Gares::Search do
82
82
 
83
83
  it 'should return the gare sncf_id.downcase correctly' do
84
84
  subject = Gares::Station.search('MONTELIMAR GARE SNCF')
85
- expect(subject.first.sncf_id.downcase).to eql('frxmk')
85
+ expect(subject.first.sncf_id.downcase).to eql('frmtl')
86
86
  end
87
87
 
88
88
  it 'should return the gare sncf_id.downcase correctly' do
@@ -98,7 +98,7 @@ describe Gares::Train do
98
98
  expect(subject.departure.delayed?).to be(false)
99
99
  end
100
100
 
101
- it "has stops", focus: true do
101
+ it "has stops" do
102
102
  expect(subject.stops.size).to eq(7)
103
103
  expect(subject.stops.first.station.name).to eq('Nogent-sur-Seine')
104
104
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gares
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.pre.pre
4
+ version: 2.0.0.pre.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Bonaud
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-01 00:00:00.000000000 Z
11
+ date: 2015-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0.13'
83
+ - !ruby/object:Gem::Dependency
84
+ name: trie
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: rake
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -210,6 +224,7 @@ files:
210
224
  - README.md
211
225
  - Rakefile
212
226
  - gares.gemspec
227
+ - lib/attribute_accessors.rb
213
228
  - lib/gares.rb
214
229
  - lib/gares/base.rb
215
230
  - lib/gares/errors.rb
@@ -218,10 +233,10 @@ files:
218
233
  - lib/gares/services.rb
219
234
  - lib/gares/station.rb
220
235
  - lib/gares/station_list.rb
221
- - lib/gares/string_extensions.rb
222
236
  - lib/gares/train.rb
223
237
  - lib/gares/train_stop.rb
224
238
  - lib/gares/version.rb
239
+ - lib/string_extensions.rb
225
240
  - spec/fixtures/frabt
226
241
  - spec/fixtures/frabt-services-vente
227
242
  - spec/fixtures/frhco
@@ -1,22 +0,0 @@
1
- require 'cgi'
2
-
3
- module Gares #:nordoc:
4
- module StringExtensions
5
- # Unescape HTML
6
- def unescape_html
7
- CGI.unescapeHTML(encode('UTF-8'))
8
- end
9
-
10
- # Strip tags
11
- def strip_tags
12
- gsub(/<\/?[^>]*>/, '')
13
- end
14
-
15
- # Strips out whitespace then tests if the string is empty.
16
- def blank?
17
- strip.empty?
18
- end unless method_defined?(:blank?)
19
- end
20
- end
21
-
22
- String.send :include, Gares::StringExtensions