transilien_microservices 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d9ce413dfd4786a986a8fe3226cef622df78e9f9
4
+ data.tar.gz: 3b672ac27a336f667d79fa1f73543d9012a84bb6
5
+ SHA512:
6
+ metadata.gz: 0c673cb9635c16509f58f0829002111cfdf40302ff62d0252f5f27dac5ec6d393f171074e1d16096224d20cedcb7d9460608689fe5fd0e8265d594d6a8258253
7
+ data.tar.gz: 70b3ebb0084748339843dd5b64fd33b4cec56d5cf1c5f37be79a2b7062171b3b0b81d5104f63a6804641914ca1e829e4c9b4eba7fdc471e1546e37a34ab0be73
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ InstalledFiles
7
+ _yardoc
8
+ coverage
9
+ doc/
10
+ lib/bundler/man
11
+ pkg
12
+ rdoc
13
+ spec/reports
14
+ test/tmp
15
+ test/version_tmp
16
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.0.0-p0
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in transilien_microservices.gemspec
4
+ gemspec
5
+
6
+ # Dev only
7
+ group :test do
8
+ gem 'rspec'
9
+ gem 'guard-rspec'
10
+ gem 'pry'
11
+ gem 'pry-doc'
12
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,67 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ transilien_microservices (0.0.1)
5
+ faraday (>= 0.8.4)
6
+ nokogiri (>= 1.5.5)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ celluloid (0.15.2)
12
+ timers (~> 1.1.0)
13
+ coderay (1.0.9)
14
+ diff-lcs (1.1.3)
15
+ faraday (0.8.4)
16
+ multipart-post (~> 1.1)
17
+ ffi (1.9.0)
18
+ formatador (0.2.4)
19
+ guard (2.1.1)
20
+ formatador (>= 0.2.4)
21
+ listen (~> 2.1)
22
+ lumberjack (~> 1.0)
23
+ pry (>= 0.9.12)
24
+ thor (>= 0.18.1)
25
+ guard-rspec (2.5.4)
26
+ guard (>= 1.1)
27
+ rspec (~> 2.11)
28
+ listen (2.1.1)
29
+ celluloid (>= 0.15.2)
30
+ rb-fsevent (>= 0.9.3)
31
+ rb-inotify (>= 0.9)
32
+ lumberjack (1.0.4)
33
+ method_source (0.8.2)
34
+ multipart-post (1.1.5)
35
+ nokogiri (1.5.9)
36
+ pry (0.9.12.2)
37
+ coderay (~> 1.0.5)
38
+ method_source (~> 0.8)
39
+ slop (~> 3.4)
40
+ pry-doc (0.4.6)
41
+ pry (>= 0.9)
42
+ yard (>= 0.8)
43
+ rb-fsevent (0.9.3)
44
+ rb-inotify (0.9.2)
45
+ ffi (>= 0.5.0)
46
+ rspec (2.12.0)
47
+ rspec-core (~> 2.12.0)
48
+ rspec-expectations (~> 2.12.0)
49
+ rspec-mocks (~> 2.12.0)
50
+ rspec-core (2.12.0)
51
+ rspec-expectations (2.12.0)
52
+ diff-lcs (~> 1.1.3)
53
+ rspec-mocks (2.12.0)
54
+ slop (3.4.6)
55
+ thor (0.18.1)
56
+ timers (1.1.0)
57
+ yard (0.8.7.2)
58
+
59
+ PLATFORMS
60
+ ruby
61
+
62
+ DEPENDENCIES
63
+ guard-rspec
64
+ pry
65
+ pry-doc
66
+ rspec
67
+ transilien_microservices!
data/Guardfile ADDED
@@ -0,0 +1,24 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec' do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+
9
+ # Rails example
10
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
11
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
12
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
13
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
14
+ watch('config/routes.rb') { "spec/routing" }
15
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
16
+
17
+ # Capybara features specs
18
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
19
+
20
+ # Turnip features and steps
21
+ watch(%r{^spec/acceptance/(.+)\.feature$})
22
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
23
+ end
24
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012-2013 Thomas Lecavelier
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,91 @@
1
+ # TransilienMicroservices
2
+
3
+ Ruby implementation of SNCF Transilien Microservices.
4
+
5
+ Here the original service documentation: http://test.data-sncf.com/index.php/transilien.html/api.22.22-micro-services.html
6
+
7
+ These services let you know the theoric offer on Transilien service.
8
+
9
+ Disclamer: The gem only intend to implements the API. I'll create a "easy" wrapper to access these data in a convenient way very soon.
10
+
11
+ ## Installation
12
+
13
+ Gem developped with ruby 2.0.0, should work with ruby 1.9.3
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ gem 'transilien_microservices'
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install transilien_microservices
26
+
27
+ ## Usage
28
+
29
+ The best way to access data is certainly querying through StopArea: start by fetching them.
30
+
31
+ stop_areas = Transilien::StopArea.find
32
+
33
+ Every Transilien "main" objects have the same attributes:
34
+
35
+ stop_areas.first.inspect
36
+ => "#<Transilien::StopArea external_code=\"DUA8738221\" name=\"LA DEFENSE GRANDE ARCHE\" >"
37
+
38
+ * "name" is a "public" name. Can't be filtered directly through Transilien API
39
+ * "external_code" is the true "key" to use in queries.
40
+
41
+ They have in bonus #payload method which return the node used to build this object.
42
+
43
+ If you want to find a commercial line that stops by two StopArea, say: Val d'Argenteuil (DUA8738179) and Paris Saint Lazare (DUA8738400) you can query this way:
44
+
45
+ val_stlaz_lines = Transilien::Line.find(stop_area_external_code: {and: ['DUA8738400', 'DUA8738179']})
46
+
47
+ Ok, but to tell the truth, I doubt that you don't bother about the way: you're going from Val to StLaz, not the inverse, so precise it:
48
+
49
+ val_to_stlaz_lines = Transilien::Line.find(destination_external_code: 'DUA8738400', stop_area_external_code: 'DUA8738179')
50
+
51
+ You get an Array of Transilien::Line fullfilling your wish.
52
+
53
+ Staying on that example, we'll stay with the "biggest" Line of the set: "Mantes la Jolie => Gare St Lazare via CONFLANS" DUA800854044
54
+ To get ALL the stops served by this Line:
55
+
56
+ Transilien::StopArea.find(line_external_code: 'DUA800854044')
57
+
58
+ Ok, that's fun. But Transilien is all about train and departures. What are the trains going from Val d’Argenteuil to Paris Saint Lazare? Transilien::VehicleJourney is all about it
59
+
60
+ instant = Time.new
61
+ start_time = Time.local(instant.year, instant.month, instant.day, 17, 30)
62
+ end_time = Time.local(instant.year, instant.month, instant.day, 18, 45)
63
+ Transilien::VehicleJourney.find stop_area_external_code: {and: ['DUA8738400', 'DUA8738179'], date: Transilien.date(instant), start_time: Transilien.time(start_time), end_time: Transilien.time(end_time) }
64
+
65
+ Yeah! Better. You still have a problem: this give you all the journey starting between start_time and end_time on date instant, but don't give a fuck to your way.
66
+
67
+ Ready to forget what you just learnt? Go back a little bit before this point: a Line instance always have at least two Route (one way, the other). And its finder understand a convenient param: CheckOrder. If set to 1, and 2 stops are given, Route returned will honor the given way by stops order:
68
+
69
+ routes_stlaz_val = Transilien::Route.find(stop_area_external_code: {and:['DUA8738400','DUA8738179']}, check_order: 1)
70
+
71
+ Here you have only Route stoping by DUA8738400 then DUA8738179, not the inverse.
72
+
73
+ Now it'll be easy to get VehicleJourney matching your needs. The same VehicleJourney will become:
74
+
75
+ Transilien::VehicleJourney.find route_external_code: routes_stlaz_val.map(&:external_code), date: Transilien.date(instant), start_time: Transilien.time(start_time), end_time: Transilien.time(end_time)
76
+
77
+ Easier, isn't it? Now take every Stop and keep only your matching StopArea: you'll get your hours of departures and arrivals :)
78
+
79
+ ## Contributing
80
+
81
+ 1. Fork it
82
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
83
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
84
+ 4. Push to the branch (`git push origin my-new-feature`)
85
+ 5. Create new Pull Request
86
+
87
+ NOTA: you're a beginner gem dev? This command may help you:
88
+
89
+ pry -Ilib -rtransilien_microservices
90
+
91
+ (you can replace pry with irb if you're not a good person…)
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,2 @@
1
+ class Transilien::Company < Transilien::MicroService
2
+ end
@@ -0,0 +1,18 @@
1
+ class Transilien::Line < Transilien::MicroService
2
+ def mode_type
3
+ @mode_type ||= Transilien::ModeType.from_node(payload.at('ModeType'), access_time)
4
+ end
5
+ def network
6
+ @network ||= Transilien::Network.from_node(payload.at('Network'), access_time)
7
+ end
8
+
9
+ # I don't have a clue what is about…
10
+ def forward
11
+ payload.at('Forward')
12
+ end
13
+
14
+ # I don't have a clue what is about…
15
+ def backward
16
+ payload.at('Backward')
17
+ end
18
+ end
@@ -0,0 +1,202 @@
1
+ require 'uri'
2
+ require 'faraday'
3
+ require 'nokogiri'
4
+ require 'time' # Time.parse for access_time in specialized instances
5
+
6
+ class Transilien::MicroService
7
+ API_HOST = 'ms.api.transilien.com'
8
+ API_URI = URI.parse("http://#{API_HOST}/")
9
+
10
+ attr_accessor :name
11
+ attr_accessor :external_code
12
+
13
+ attr_accessor :access_time
14
+ attr_accessor :payload
15
+
16
+ class << self
17
+
18
+ Default_cache_duration = 300 # in second
19
+
20
+ attr_accessor :caches
21
+ attr_accessor :query_cache
22
+
23
+ def http(uri = API_URI)
24
+ @http ||= Faraday.new(:url => uri) do |faraday|
25
+ # TODO give option to setup faraday
26
+ faraday.request :url_encoded # form-encode POST params
27
+ #faraday.response :logger # log requests to STDOUT
28
+ faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
29
+ end
30
+ end
31
+
32
+ def find_from_full_query_cache(filters)
33
+ @query_cache ||= {}
34
+ if filters[:force_refresh]
35
+ @query_cache.delete(filters.to_s)
36
+ end
37
+ if @query_cache[filters.to_s] && (@query_cache[filters.to_s][:cached_at].to_i + Default_cache_duration > Time.now.to_i)
38
+ return @query_cache[filters.to_s][:payload]
39
+ end
40
+ end
41
+
42
+ # Iterative search on per instance search. That's HARD.
43
+ # WIP idea: since filters are prefixed by operator (AND by default), we can deal key by key. Collection on the first run is the matching
44
+ # instances on that uniq key. The result will be the last collection returned. Potentially nil.
45
+ def find_from_query_caches(filters, collection = nil, operator = nil)
46
+ if collection.nil?
47
+ # FIRST RUN
48
+ filters.keys.each do |key|
49
+ collection = [query_cache({key: key, value: filters[key]})]
50
+ end
51
+ end
52
+
53
+ end
54
+
55
+ # /?action=LineList&StopAreaExternalCode=DUA8754309;DUA8754513|and&RouteExternalCode=DUA8008030781013;DUA8008031050001|or
56
+ # -> find(:stop_area_external_code => { :and => ['DUA8754309', 'DUA8754513'] }, :route_external_code => { :or => ['DUA8008030781013', 'DUA8008031050001'] })
57
+ def find(filters = {}, options = {})
58
+ collection = find_from_full_query_cache(filters)
59
+ collection ||= find_from_query_caches(filters)
60
+
61
+ self.filters = filters
62
+ response = self.http.get(action_param, params)
63
+ puts('== Request: ')
64
+ puts(action_param.inspect)
65
+ puts(params.inspect)
66
+ puts(response.env[:url].inspect)
67
+ body = response.body
68
+ collection = []
69
+ doc = Nokogiri.XML(body)
70
+ return errors(doc) unless errors(doc).empty?
71
+ request_time = Time.parse(response.headers[:date])
72
+ doc.xpath(action_instance_xpath).each do |node|
73
+ item = from_node(node, request_time)
74
+ collection << item
75
+ end
76
+ @query_cache[filters.to_s] = { payload: collection, cached_at: request_time }
77
+ collection
78
+ end
79
+
80
+ def from_node(node, access_time)
81
+ item = new
82
+ item.payload = node
83
+
84
+ # common stuff
85
+ item.external_code = node["#{action_component}ExternalCode"]
86
+ item.name = node["#{action_component}Name"]
87
+ item.access_time = access_time
88
+
89
+ cache_it(item)
90
+
91
+ item
92
+ end
93
+
94
+ def cache_keys
95
+ [:name, :external_code]
96
+ end
97
+
98
+ def cache_it(item)
99
+ @caches ||= {}
100
+ cache_keys.each do |k|
101
+ @caches[k] ||= {}
102
+ @caches[k][item.send(k)] = item
103
+ end
104
+ item
105
+ end
106
+
107
+ def query_cache(query = nil)
108
+ return @caches unless query
109
+ q = query || {}
110
+ q[:key] ||= 'name'
111
+ return nil if @caches.nil? || @caches[action_component].nil?
112
+ (@caches[action_component][q[:key]] || []).each do |item|
113
+ return item if item.name == q[:value]
114
+ end
115
+ end
116
+
117
+ def errors(doc)
118
+ @errors ||= begin
119
+ @errors = []
120
+ doc.xpath('/Errors/Error').each do |err_node|
121
+ err = Transilien::MicroService::Error.new
122
+ err.code = err_node['code']
123
+ err.message = err_node.content
124
+ err.request = { params: params, action: action_param}
125
+ @errors << err
126
+ end
127
+ @errors
128
+ end
129
+ end
130
+
131
+
132
+ def action_component
133
+ self.to_s.split('::').last
134
+ end
135
+
136
+ def action
137
+ "#{action_component}List"
138
+ end
139
+
140
+ def action_param
141
+ "/?action=#{action}"
142
+ end
143
+
144
+ def action_instance_xpath
145
+ "/Action#{action}/#{action}/#{action_component}"
146
+ end
147
+
148
+ def params
149
+ return {} if filters.empty?
150
+ final = {}
151
+ @filters.each do |filter, filter_value|
152
+ final_filter = filter.to_s.split('_').map(&:capitalize).join
153
+ if filter_value.is_a?(Hash)
154
+ filter_value.each_pair do |operator, values|
155
+ ok_operators = [:and, :or]
156
+ raise ArgumentError.new("Operator #{operator} unknown. Should be one of #{ok_operators.inspect}.") unless ok_operators.include?(operator.to_sym)
157
+ final_values = [values].flatten.compact.join(';')
158
+ final[final_filter] = "#{final_values}|#{operator.to_s}"
159
+ end
160
+ elsif filter_value.is_a?(Array)
161
+ # By default, consider OR operator when values are only an array
162
+ final[final_filter] = "#{filter_value.join(';')}|or"
163
+ else
164
+ final[final_filter] = filter_value
165
+ end
166
+ end
167
+ final
168
+ end
169
+
170
+ def filters
171
+ @filters ||= {}
172
+ end
173
+
174
+ def filters=(new_filters)
175
+ raise ArgumentError.new('filters= -> new_filters MUST be a hash, even empty') unless new_filters.is_a?(Hash)
176
+ @filters = new_filters
177
+ end
178
+
179
+ def add_filters()
180
+ self.filters
181
+ end
182
+
183
+ end
184
+
185
+ def to_s
186
+ "#<#{self.class.to_s} external_code=#{@external_code.inspect} name=#{@name.inspect} >"
187
+ end
188
+
189
+ class Error
190
+ attr_accessor :code, :message, :payload, :request
191
+ end
192
+
193
+ end
194
+
195
+ class Transilien::FakeMicroService < Transilien::MicroService
196
+
197
+ class << self
198
+ def http(dummy=nil)
199
+ raise "FakeMicroService: you can't request a connection a connection. Use #from_node instead"
200
+ end
201
+ end
202
+ end
@@ -0,0 +1,5 @@
1
+ class Transilien::Mode < Transilien::MicroService
2
+ def mode_type
3
+ @mode_type ||= Transilien::ModeType.find(mode_type_external_code: payload['ModeTypeExternalCode']).try(:first)
4
+ end
5
+ end
@@ -0,0 +1,2 @@
1
+ class Transilien::ModeType < Transilien::MicroService
2
+ end
@@ -0,0 +1,2 @@
1
+ class Transilien::Network < Transilien::MicroService
2
+ end
@@ -0,0 +1,13 @@
1
+ class Transilien::Route < Transilien::MicroService
2
+ def line
3
+ @line ||= Transilien::Line.from_node(payload.at('Line'), access_time)
4
+ end
5
+ end
6
+
7
+ class Transilien::City < Transilien::FakeMicroService
8
+ attr_accessor :code
9
+ def from_node(node, access_time)
10
+ item = super(node, access_time)
11
+ item.code(node['CityCode'])
12
+ end
13
+ end
@@ -0,0 +1,27 @@
1
+ class Transilien::Stop < Transilien::FakeMicroService
2
+ attr_accessor :stop_time, :arrival_time, :name_at_stop
3
+
4
+ class << self
5
+ def from_node(node, access_time)
6
+ item = new
7
+ item.payload = node
8
+
9
+ stop_node = node.at('StopTime')
10
+ item.stop_time = !stop_node.children.empty? && ::Transilien::Time.from_node(stop_node, access_time)
11
+
12
+ arrival_node = node.at('StopArrivalTime')
13
+ item.arrival_time = !arrival_node.children.empty? && ::Transilien::Time.from_node(arrival_node, access_time)
14
+
15
+ item.name_at_stop = node.at('VehicleJourneyNameAtStop') && node.at('VehicleJourneyNameAtStop').text
16
+ item
17
+ end
18
+ end
19
+
20
+ def stop_point
21
+ @stop_point ||= Transilien::StopPoint.from_node(payload.at('StopPoint'), access_time)
22
+ end
23
+
24
+ def name # objective: enable caching
25
+ "#{stop_time.name}||#{arrival_time.name}"
26
+ end
27
+ end
@@ -0,0 +1,52 @@
1
+ class Transilien::StopArea < Transilien::MicroService
2
+ def main_stop_area
3
+ @main_stop_area ||= payload['MainStopArea'] == '1'
4
+ end
5
+
6
+ def multi_modal
7
+ @multi_modal ||= payload['MultiModal'] == '1'
8
+ end
9
+
10
+ def car_park
11
+ @car_park ||= payload['CarPark'] == '1'
12
+ end
13
+
14
+ def main_connection
15
+ @main_connection ||= payload['MainConnection'] == '1'
16
+ end
17
+
18
+ def additional_data
19
+ @additional_data ||= payload['AdditionalData']
20
+ end
21
+
22
+ def resa_rail_code
23
+ @resa_rail_code ||= payload['ResaRailCode']
24
+ end
25
+
26
+ def coord
27
+ @coord ||= {
28
+ x: payload.at('Coord').at('CoordX').content.sub(',','.').to_f,
29
+ y: payload.at('Coord').at('CoordY').content.sub(',','.').to_f
30
+ }
31
+ end
32
+
33
+ def modes
34
+ @modes ||= begin
35
+ modes = []
36
+ payload.at('ModeList').children.each do |mode|
37
+ modes << Transilien::ModeType.from_node(mode, access_time)
38
+ end
39
+ modes
40
+ end
41
+ end
42
+ alias_method :mode_types, :modes # ModeList ≠ ModeTypeList : bad naming from SNCF
43
+
44
+ def city
45
+ @city ||= Transilien::City.from_node(payload.at('City'), access_time)
46
+ end
47
+
48
+ def hangs
49
+ @hangs ||= payload.at('HangList').children
50
+ end
51
+
52
+ end
@@ -0,0 +1,41 @@
1
+ class Transilien::StopPoint < Transilien::MicroService
2
+ def fare_zone
3
+ @fare_zone ||= payload['FareZone']
4
+ end
5
+
6
+ def address
7
+ payload.at('StopPointAddress')
8
+ end
9
+ alias_method :stop_point_address, :address
10
+
11
+ def equipment
12
+ @equipment ||= {
13
+ sheltered: (payload.at('Equipment')['Sheltered'] == 'True'),
14
+ mimp_access: (payload.at('Equipment')['MIPAccess'] == 'True'),
15
+ elevator: (payload.at('Equipment')['Elevator'] == 'True'),
16
+ escalator: (payload.at('Equipment')['Escalator'] == 'True'),
17
+ bike_accepted: (payload.at('Equipment')['BikeAccepted'] == 'True'),
18
+ bike_depot: (payload.at('Equipment')['BikeDepot'] == 'True')
19
+ }
20
+ end
21
+
22
+ def mode
23
+ @mode ||= Transilien::Mode.from_node(payload.at('Mode'), access_time)
24
+ end
25
+
26
+ def city
27
+ @city ||= Transilien::City.from_node(payload.at('City'), access_time)
28
+ end
29
+
30
+ def stop_area
31
+ #@stop_area ||= Transilien::StopArea.from_node(payload.at('StopArea'), access_time)
32
+ @stop_area ||= Transilien::StopArea.find(stop_area_external_code: payload.at('StopArea')['StopAreaExternalCode']).first
33
+ end
34
+
35
+ def coord
36
+ @coord ||= {
37
+ x: payload.at('Coord').at('CoordX').content.sub(',','.').to_f,
38
+ y: payload.at('Coord').at('CoordY').content.sub(',','.').to_f
39
+ }
40
+ end
41
+ end
@@ -0,0 +1,20 @@
1
+ class Transilien::Time < Transilien::FakeMicroService
2
+ attr_accessor :total_seconds, :day, :hour, :minute
3
+
4
+ class << self
5
+ def from_node(node, access_time)
6
+ item = new
7
+ item.payload = node
8
+
9
+ item.total_seconds = node.at('TotalSeconds').text
10
+ item.day = node.at('Day').text
11
+ item.hour = node.at('Hour').text
12
+ item.minute = node.at('Minute').text
13
+ item
14
+ end
15
+ end
16
+
17
+ def name # objective: enable caching
18
+ "#{day}:#{hour}:#{minutes}|#{total_seconds}"
19
+ end
20
+ end
@@ -0,0 +1,26 @@
1
+ class Transilien::VehicleJourney < Transilien::MicroService
2
+ def route
3
+ @route ||= Transilien::Route.from_node(payload.at('Route'), access_time)
4
+ end
5
+ def mode
6
+ @mode ||= Transilien::Mode.from_node(payload.at('Mode'), access_time)
7
+ end
8
+ def company
9
+ @company ||= Transilien::Company.from_node(payload.at('Company'), access_time)
10
+ end
11
+ def vehicle
12
+ @vehicle ||= payload.at('Vehicle')
13
+ end
14
+ def validity_pattern
15
+ @validity_pattern ||= payload.at('ValidityPattern')
16
+ end
17
+
18
+ def stops
19
+ @stops ||= begin
20
+ stops_nodes = payload.at('StopList')
21
+ stops_nodes.children.map do |stop_node|
22
+ Transilien::Stop.from_node(stop_node, access_time)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,3 @@
1
+ module Transilien
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,22 @@
1
+ require "./lib/transilien/version.rb"
2
+ require "./lib/transilien/micro_service.rb"
3
+ require "./lib/transilien/time.rb"
4
+ require "./lib/transilien/network.rb"
5
+ require "./lib/transilien/mode_type.rb"
6
+ require "./lib/transilien/line.rb"
7
+ require "./lib/transilien/route.rb"
8
+ require "./lib/transilien/stop_point.rb"
9
+ require "./lib/transilien/stop_area.rb"
10
+ require "./lib/transilien/vehicle_journey.rb"
11
+ require "./lib/transilien/mode.rb"
12
+ require "./lib/transilien/company.rb"
13
+ require "./lib/transilien/stop.rb"
14
+
15
+ module Transilien
16
+ def self.date(time)
17
+ time.strftime('%Y|%m|%d')
18
+ end
19
+ def self.time(time)
20
+ time.strftime('%H|%M')
21
+ end
22
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+ describe Transilien::MicroService do
3
+ it 'should generate empty params for nothing' do
4
+ Transilien::MicroService.filters = {}
5
+ Transilien::MicroService.params.empty?.should eq(true)
6
+ end
7
+
8
+ it 'should generate correct params for one simple filter' do
9
+ Transilien::MicroService.filters = {:network_external_code => 'DU804'}
10
+ Transilien::MicroService.params.should eq({'NetworkExternalCode' => 'DU804'})
11
+ end
12
+
13
+ it 'should generate correct params for two simple filters' do
14
+ Transilien::MicroService.filters = {:network_external_code => 'DU804', :route_external_code => 'DUA8008030781013'}
15
+ Transilien::MicroService.params.should eq({'NetworkExternalCode' => 'DU804', 'RouteExternalCode' => 'DUA8008030781013'})
16
+ end
17
+
18
+ it 'should generate correct params for one simple filter with Array, or is the default logic operator for arrays' do
19
+ Transilien::MicroService.filters = {:network_external_code => ['DU804', 'DU805']}
20
+ Transilien::MicroService.params.should eq({'NetworkExternalCode' => 'DU804;DU805|or'})
21
+ end
22
+
23
+ it 'should generate correct params for two simple filters with Array, or is the default logic operator for arrays' do
24
+ Transilien::MicroService.filters = {:network_external_code => ['DU804', 'DU805'], :route_external_code => ['DUA8008030781013', 'DUA8008031050001']}
25
+ Transilien::MicroService.params.should eq({'NetworkExternalCode' => 'DU804;DU805|or', 'RouteExternalCode' => 'DUA8008030781013;DUA8008031050001|or'})
26
+ end
27
+
28
+ it 'should generate correct params for one complex filter' do
29
+ Transilien::MicroService.filters = {:network_external_code => { :and => ['DU804', 'DU805']}}
30
+ Transilien::MicroService.params.should eq({'NetworkExternalCode' => 'DU804;DU805|and'})
31
+ end
32
+
33
+ it 'should generate correct params for two complex filters' do
34
+ Transilien::MicroService.filters = {:network_external_code => { :and => ['DU804', 'DU805']}, :route_external_code => { :or => ['DUA8008030781013', 'DUA8008031050001']}}
35
+ Transilien::MicroService.params.should eq({'NetworkExternalCode' => 'DU804;DU805|and', 'RouteExternalCode' => 'DUA8008030781013;DUA8008031050001|or'})
36
+ end
37
+
38
+ it 'shoud generate correct params for a complex filter and a simple one' do
39
+ Transilien::MicroService.filters = {:stop_area_external_code => { :and => ['DUA8738400', 'DUA8738179']}, date: '2013|12|19', start_time: '17|00', end_time: '22|30'}
40
+ Transilien::MicroService.params.should eq({'StopAreaExternalCode' => 'DUA8738400;DUA8738179|and', 'Date' => '2013|12|19', 'StartTime' => '17|00', 'EndTime' => '22|30'})
41
+ end
42
+ end
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'transilien_microservices' # and any other gems you need
5
+
6
+ RSpec.configure do |config|
7
+ # some (optional) config here
8
+ end
@@ -0,0 +1 @@
1
+ <?xml version="1.0" encoding="ISO-8859-1"?><ActionVehicleJourneyList><Params Function="api"><SafeMode>0</SafeMode><action>PTReferential</action><RequestedType>vehiclejourneylist</RequestedType><routeexternalcode>DUA8008540420003;DUA8008540430008;DUA8008540430010;DUA8008540430005;DUA8008544000030;DUA8008540440001|or</routeexternalcode><date>2013|10|24</date><starttime>18|19</starttime><endtime>18|21</endtime><networkexternalcode>dua801;dua802;dua803;dua804;dua805;dua850;dua851;dua852;dua853;dua854;dua855</networkexternalcode><interface>1_10</interface><login>opendata</login></Params><VehicleJourneyList VehicleJourneyCount="1"><VehicleJourney VehicleJourneyIdx="391578" VehicleJourneyId="391577" VehicleJourneyName="GETO" VehicleJourneyRouteIdx="9991" VehicleJourneyExternalCode="DUASN137131F01002" IsAdapted="0"><Route RouteIdx="9991" RouteId="9990" RouteName="Gare St Lazare =&gt; Gisors Via Montgeroult" RouteExternalCode="DUA8008540430010" IsForward="1" RouteLineIdx="1660" IsFrequence="0" IsAdapted="0"><Line LineIdx="1660" LineId="1659" LineName="Gare St Lazare =&gt; Gisors Via Montgeroult" LineCode="J" LineExternalCode="DUA800854043" LineAdditionalData="" SortOrder="1660" LineColor="000000" HasAdaptedRoute="0"><ModeType ModeTypeIdx="15" ModeTypeExternalCode="RapidTransit" ModeTypeName="Train de banlieue / RER"/><Network NetworkIdx="76" NetworkId="8" NetworkName="Paris St Lazare" NetworkExternalCode="DUA854"></Network><Forward ForwardName="A"></Forward><Backward BackwardName=""></Backward></Line></Route><Mode ModeIdx="12" ModeId="12" ModeName="Train" ModeExternalCode="Train" ModeTypeExternalCode="RapidTransit"/><Company CompanyIdx="50" CompanyId="49" CompanyName="SNCF" CompanyExternalCode="DUA800"/><Vehicle VehicleIdx="0" VehicleId="-1" VehicleName="" VehicleExternalCode="" MIPAccess="False" BikeAccepted="False" AirConditioned="False"/><ValidityPattern ValidityPatternBeginningDay="2013|09|27" IsAdapted="0" ValidityPatternIdx="9987">000000000000000000000100111110011110001111100011110011111001111100111110011111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000</ValidityPattern><StopList StopCount="15"><Stop StopIdx="6981526" StopPointIdx="1889" VehicleJourneyIdx="391578" HourNumber="0" MinuteNumber="0" DestinationPos="-1" ODTIdx="0" ODTPos="-1" ValidityPatternSetCommentPos="0" StopOrder="0" VehicleIdx="0"><StopTime><TotalSeconds>66000</TotalSeconds><Day>0</Day><Hour>18</Hour><Minute>20</Minute></StopTime><StopArrivalTime/><StopPoint StopPointIdx="1889" StopPointId="39699" StopPointName="PARIS SAINT-LAZARE" StopPointExternalCode="DUA8738400" FareZone="1"><StopPointAddress StopPointAddressName="" StopPointAddressNumber="" StopPointAddressTypeName=""/><Equipment Sheltered="False" MIPAccess="False" Elevator="False" Escalator="False" BikeAccepted="False" BikeDepot="False"/><Mode ModeIdx="12" ModeId="12" ModeName="Train" ModeExternalCode="Train" ModeTypeExternalCode="RapidTransit"/><City CityIdx="1" CityId="0" CityName="Paris" CityExternalCode="75056" CityCode="75004"></City><StopArea StopAreaIdx="592" StopAreaId="317" StopAreaName="PARIS SAINT-LAZARE" StopAreaExternalCode="DUA8738400" MainStopArea="1" MultiModal="0" CarPark="0" MainConnection="1" AdditionalData="" ResaRailCode=""><Coord><CoordX>599136,94</CoordX><CoordY>2430773,22</CoordY></Coord></StopArea><Coord><CoordX>599140,00</CoordX><CoordY>2430792,00</CoordY></Coord></StopPoint><VehicleJourneyNameAtStop>37131</VehicleJourneyNameAtStop></Stop><Stop StopIdx="7162918" StopPointIdx="39148" VehicleJourneyIdx="391578" HourNumber="0" MinuteNumber="0" DestinationPos="-1" ODTIdx="0" ODTPos="-1" ValidityPatternSetCommentPos="0" StopOrder="1" VehicleIdx="0"><StopTime><TotalSeconds>66960</TotalSeconds><Day>0</Day><Hour>18</Hour><Minute>36</Minute></StopTime><StopArrivalTime><TotalSeconds>66900</TotalSeconds><Day>0</Day><Hour>18</Hour><Minute>35</Minute></StopArrivalTime><StopPoint StopPointIdx="39148" StopPointId="39671" StopPointName="HERBLAY" StopPointExternalCode="DUA8738188" FareZone="4"><StopPointAddress StopPointAddressName="" StopPointAddressNumber="" StopPointAddressTypeName=""/><Equipment Sheltered="False" MIPAccess="False" Elevator="False" Escalator="False" BikeAccepted="False" BikeDepot="False"/><Mode ModeIdx="3" ModeId="3" ModeName="BUS" ModeExternalCode="RATP" ModeTypeExternalCode="Bus"/><City CityIdx="1185" CityId="1184" CityName="Herblay" CityExternalCode="95306" CityCode="95220"></City><StopArea StopAreaIdx="16806" StopAreaId="17633" StopAreaName="HERBLAY" StopAreaExternalCode="DUA8738188" MainStopArea="1" MultiModal="0" CarPark="0" MainConnection="0" AdditionalData="" ResaRailCode=""><Coord><CoordX>587165,67</CoordX><CoordY>2443663,10</CoordY></Coord></StopArea><Coord><CoordX>587212,66</CoordX><CoordY>2443585,69</CoordY></Coord></StopPoint></Stop><Stop StopIdx="7219144" StopPointIdx="13263" VehicleJourneyIdx="391578" HourNumber="0" MinuteNumber="0" DestinationPos="-1" ODTIdx="0" ODTPos="-1" ValidityPatternSetCommentPos="0" StopOrder="2" VehicleIdx="0"><StopTime><TotalSeconds>67260</TotalSeconds><Day>0</Day><Hour>18</Hour><Minute>41</Minute></StopTime><StopArrivalTime><TotalSeconds>67200</TotalSeconds><Day>0</Day><Hour>18</Hour><Minute>40</Minute></StopArrivalTime><StopPoint StopPointIdx="13263" StopPointId="39672" StopPointName="CONFLANS SAINTE-HONORINE" StopPointExternalCode="DUA8738189" FareZone="5"><StopPointAddress StopPointAddressName="" StopPointAddressNumber="" StopPointAddressTypeName=""/><Equipment Sheltered="False" MIPAccess="False" Elevator="False" Escalator="False" BikeAccepted="False" BikeDepot="False"/><Mode ModeIdx="3" ModeId="3" ModeName="BUS" ModeExternalCode="RATP" ModeTypeExternalCode="Bus"/><City CityIdx="579" CityId="578" CityName="Conflans-Sainte-Honorine" CityExternalCode="78172" CityCode="78700"></City><StopArea StopAreaIdx="5848" StopAreaId="6101" StopAreaName="CONFLANS SAINTE-HONORINE" StopAreaExternalCode="DUA8738189" MainStopArea="1" MultiModal="0" CarPark="0" MainConnection="0" AdditionalData="" ResaRailCode=""><Coord><CoordX>582543,85</CoordX><CoordY>2444390,69</CoordY></Coord></StopArea><Coord><CoordX>582518,32</CoordX><CoordY>2444303,58</CoordY></Coord></StopPoint></Stop><Stop StopIdx="7307988" StopPointIdx="40167" VehicleJourneyIdx="391578" HourNumber="0" MinuteNumber="0" DestinationPos="-1" ODTIdx="0" ODTPos="-1" ValidityPatternSetCommentPos="0" StopOrder="3" VehicleIdx="0"><StopTime><TotalSeconds>67740</TotalSeconds><Day>0</Day><Hour>18</Hour><Minute>49</Minute></StopTime><StopArrivalTime><TotalSeconds>67680</TotalSeconds><Day>0</Day><Hour>18</Hour><Minute>48</Minute></StopArrivalTime><StopPoint StopPointIdx="40167" StopPointId="39565" StopPointName="PONTOISE" StopPointExternalCode="DUA8727613" FareZone="5"><StopPointAddress StopPointAddressName="" StopPointAddressNumber="" StopPointAddressTypeName=""/><Equipment Sheltered="False" MIPAccess="False" Elevator="False" Escalator="False" BikeAccepted="False" BikeDepot="False"/><Mode ModeIdx="3" ModeId="3" ModeName="BUS" ModeExternalCode="RATP" ModeTypeExternalCode="Bus"/><City CityIdx="1236" CityId="1235" CityName="Pontoise" CityExternalCode="95500" CityCode="95300"></City><StopArea StopAreaIdx="17260" StopAreaId="18082" StopAreaName="PONTOISE" StopAreaExternalCode="DUA8727613" MainStopArea="1" MultiModal="0" CarPark="0" MainConnection="1" AdditionalData="" ResaRailCode=""><Coord><CoordX>582304,73</CoordX><CoordY>2449874,50</CoordY></Coord></StopArea><Coord><CoordX>582346,60</CoordX><CoordY>2449869,95</CoordY></Coord></StopPoint></Stop><Stop StopIdx="7352269" StopPointIdx="39920" VehicleJourneyIdx="391578" HourNumber="0" MinuteNumber="0" DestinationPos="-1" ODTIdx="0" ODTPos="-1" ValidityPatternSetCommentPos="0" StopOrder="4" VehicleIdx="0"><StopTime><TotalSeconds>67980</TotalSeconds><Day>0</Day><Hour>18</Hour><Minute>53</Minute></StopTime><StopArrivalTime><TotalSeconds>67980</TotalSeconds><Day>0</Day><Hour>18</Hour><Minute>53</Minute></StopArrivalTime><StopPoint StopPointIdx="39920" StopPointId="39632" StopPointName="OSNY" StopPointExternalCode="DUA8738114" FareZone="5"><StopPointAddress StopPointAddressName="" StopPointAddressNumber="" StopPointAddressTypeName=""/><Equipment Sheltered="False" MIPAccess="False" Elevator="False" Escalator="False" BikeAccepted="False" BikeDepot="False"/><Mode ModeIdx="12" ModeId="12" ModeName="Train" ModeExternalCode="Train" ModeTypeExternalCode="RapidTransit"/><City CityIdx="1227" CityId="1226" CityName="Osny" CityExternalCode="95476" CityCode="95520"></City><StopArea StopAreaIdx="17177" StopAreaId="18009" StopAreaName="OSNY" StopAreaExternalCode="DUA8738114" MainStopArea="1" MultiModal="0" CarPark="0" MainConnection="0" AdditionalData="" ResaRailCode=""><Coord><CoordX>579578,22</CoordX><CoordY>2451707,92</CoordY></Coord></StopArea><Coord><CoordX>579625,09</CoordX><CoordY>2451695,58</CoordY></Coord></StopPoint></Stop><Stop StopIdx="7395775" StopPointIdx="37513" VehicleJourneyIdx="391578" HourNumber="0" MinuteNumber="0" DestinationPos="-1" ODTIdx="0" ODTPos="-1" ValidityPatternSetCommentPos="0" StopOrder="5" VehicleIdx="0"><StopTime><TotalSeconds>68220</TotalSeconds><Day>0</Day><Hour>18</Hour><Minute>57</Minute></StopTime><StopArrivalTime><TotalSeconds>68220</TotalSeconds><Day>0</Day><Hour>18</Hour><Minute>57</Minute></StopArrivalTime><StopPoint StopPointIdx="37513" StopPointId="39633" StopPointName="BOISSY L'AILLERIE" StopPointExternalCode="DUA8738115" FareZone="5"><StopPointAddress StopPointAddressName="" StopPointAddressNumber="" StopPointAddressTypeName=""/><Equipment Sheltered="False" MIPAccess="False" Elevator="False" Escalator="False" BikeAccepted="False" BikeDepot="False"/><Mode ModeIdx="12" ModeId="12" ModeName="Train" ModeExternalCode="Train" ModeTypeExternalCode="RapidTransit"/><City CityIdx="1123" CityId="1122" CityName="Boissy-l'Aillerie" CityExternalCode="95078" CityCode="95650"></City><StopArea StopAreaIdx="16097" StopAreaId="16902" StopAreaName="BOISSY L'AILLERIE" StopAreaExternalCode="DUA8738115" MainStopArea="1" MultiModal="0" CarPark="0" MainConnection="0" AdditionalData="" ResaRailCode=""><Coord><CoordX>577234,07</CoordX><CoordY>2453083,08</CoordY></Coord></StopArea><Coord><CoordX>577221,21</CoordX><CoordY>2453137,24</CoordY></Coord></StopPoint></Stop><Stop StopIdx="7428308" StopPointIdx="39612" VehicleJourneyIdx="391578" HourNumber="0" MinuteNumber="0" DestinationPos="-1" ODTIdx="0" ODTPos="-1" ValidityPatternSetCommentPos="0" StopOrder="6" VehicleIdx="0"><StopTime><TotalSeconds>68400</TotalSeconds><Day>0</Day><Hour>19</Hour><Minute>00</Minute></StopTime><StopArrivalTime><TotalSeconds>68400</TotalSeconds><Day>0</Day><Hour>19</Hour><Minute>00</Minute></StopArrivalTime><StopPoint StopPointIdx="39612" StopPointId="39634" StopPointName="MONTGEROULT COURCELLES" StopPointExternalCode="DUA8738116" FareZone="5"><StopPointAddress StopPointAddressName="" StopPointAddressNumber="" StopPointAddressTypeName=""/><Equipment Sheltered="False" MIPAccess="False" Elevator="False" Escalator="False" BikeAccepted="False" BikeDepot="False"/><Mode ModeIdx="12" ModeId="12" ModeName="Train" ModeExternalCode="Train" ModeTypeExternalCode="RapidTransit"/><City CityIdx="1210" CityId="1209" CityName="Montgeroult" CityExternalCode="95422" CityCode="95650"></City><StopArea StopAreaIdx="17040" StopAreaId="17878" StopAreaName="MONTGEROULT COURCELLES" StopAreaExternalCode="DUA8738116" MainStopArea="1" MultiModal="0" CarPark="0" MainConnection="0" AdditionalData="" ResaRailCode=""><Coord><CoordX>575713,63</CoordX><CoordY>2453675,60</CoordY></Coord></StopArea><Coord><CoordX>575670,74</CoordX><CoordY>2453661,18</CoordY></Coord></StopPoint></Stop><Stop StopIdx="7471886" StopPointIdx="41239" VehicleJourneyIdx="391578" HourNumber="0" MinuteNumber="0" DestinationPos="-1" ODTIdx="0" ODTPos="-1" ValidityPatternSetCommentPos="0" StopOrder="7" VehicleIdx="0"><StopTime><TotalSeconds>68640</TotalSeconds><Day>0</Day><Hour>19</Hour><Minute>04</Minute></StopTime><StopArrivalTime><TotalSeconds>68640</TotalSeconds><Day>0</Day><Hour>19</Hour><Minute>04</Minute></StopArrivalTime><StopPoint StopPointIdx="41239" StopPointId="39635" StopPointName="US" StopPointExternalCode="DUA8738117" FareZone="5"><StopPointAddress StopPointAddressName="" StopPointAddressNumber="" StopPointAddressTypeName=""/><Equipment Sheltered="False" MIPAccess="False" Elevator="False" Escalator="False" BikeAccepted="False" BikeDepot="False"/><Mode ModeIdx="12" ModeId="12" ModeName="Train" ModeExternalCode="Train" ModeTypeExternalCode="RapidTransit"/><City CityIdx="1265" CityId="1264" CityName="Us" CityExternalCode="95625" CityCode="95450"></City><StopArea StopAreaIdx="17670" StopAreaId="18535" StopAreaName="US" StopAreaExternalCode="DUA8738117" MainStopArea="1" MultiModal="0" CarPark="0" MainConnection="0" AdditionalData="" ResaRailCode=""><Coord><CoordX>573255,15</CoordX><CoordY>2455803,84</CoordY></Coord></StopArea><Coord><CoordX>573255,15</CoordX><CoordY>2455803,84</CoordY></Coord></StopPoint></Stop><Stop StopIdx="7514946" StopPointIdx="40851" VehicleJourneyIdx="391578" HourNumber="0" MinuteNumber="0" DestinationPos="-1" ODTIdx="0" ODTPos="-1" ValidityPatternSetCommentPos="0" StopOrder="8" VehicleIdx="0"><StopTime><TotalSeconds>68880</TotalSeconds><Day>0</Day><Hour>19</Hour><Minute>08</Minute></StopTime><StopArrivalTime><TotalSeconds>68880</TotalSeconds><Day>0</Day><Hour>19</Hour><Minute>08</Minute></StopArrivalTime><StopPoint StopPointIdx="40851" StopPointId="39636" StopPointName="SANTEUIL LE PERCHAY" StopPointExternalCode="DUA8738118" FareZone="5"><StopPointAddress StopPointAddressName="" StopPointAddressNumber="" StopPointAddressTypeName=""/><Equipment Sheltered="False" MIPAccess="False" Elevator="False" Escalator="False" BikeAccepted="False" BikeDepot="False"/><Mode ModeIdx="12" ModeId="12" ModeName="Train" ModeExternalCode="Train" ModeTypeExternalCode="RapidTransit"/><City CityIdx="1255" CityId="1254" CityName="Santeuil" CityExternalCode="95584" CityCode="95640"></City><StopArea StopAreaIdx="17515" StopAreaId="18374" StopAreaName="SANTEUIL LE PERCHAY" StopAreaExternalCode="DUA8738118" MainStopArea="1" MultiModal="0" CarPark="0" MainConnection="0" AdditionalData="" ResaRailCode=""><Coord><CoordX>571574,93</CoordX><CoordY>2458528,71</CoordY></Coord></StopArea><Coord><CoordX>571718,79</CoordX><CoordY>2458460,14</CoordY></Coord></StopPoint></Stop><Stop StopIdx="7567792" StopPointIdx="37934" VehicleJourneyIdx="391578" HourNumber="0" MinuteNumber="0" DestinationPos="-1" ODTIdx="0" ODTPos="-1" ValidityPatternSetCommentPos="0" StopOrder="9" VehicleIdx="0"><StopTime><TotalSeconds>69180</TotalSeconds><Day>0</Day><Hour>19</Hour><Minute>13</Minute></StopTime><StopArrivalTime><TotalSeconds>69120</TotalSeconds><Day>0</Day><Hour>19</Hour><Minute>12</Minute></StopArrivalTime><StopPoint StopPointIdx="37934" StopPointId="39637" StopPointName="CHARS" StopPointExternalCode="DUA8738119" FareZone="5"><StopPointAddress StopPointAddressName="" StopPointAddressNumber="" StopPointAddressTypeName=""/><Equipment Sheltered="False" MIPAccess="False" Elevator="False" Escalator="False" BikeAccepted="False" BikeDepot="False"/><Mode ModeIdx="12" ModeId="12" ModeName="Train" ModeExternalCode="Train" ModeTypeExternalCode="RapidTransit"/><City CityIdx="1137" CityId="1136" CityName="Chars" CityExternalCode="95142" CityCode="95750"></City><StopArea StopAreaIdx="16228" StopAreaId="17039" StopAreaName="CHARS" StopAreaExternalCode="DUA8738119" MainStopArea="1" MultiModal="0" CarPark="0" MainConnection="0" AdditionalData="" ResaRailCode=""><Coord><CoordX>570834,99</CoordX><CoordY>2462829,40</CoordY></Coord></StopArea><Coord><CoordX>570834,99</CoordX><CoordY>2462829,40</CoordY></Coord></StopPoint></Stop><Stop StopIdx="7620012" StopPointIdx="41587" VehicleJourneyIdx="391578" HourNumber="0" MinuteNumber="0" DestinationPos="-1" ODTIdx="0" ODTPos="-1" ValidityPatternSetCommentPos="0" StopOrder="10" VehicleIdx="0"><StopTime><TotalSeconds>69480</TotalSeconds><Day>0</Day><Hour>19</Hour><Minute>18</Minute></StopTime><StopArrivalTime><TotalSeconds>69420</TotalSeconds><Day>0</Day><Hour>19</Hour><Minute>17</Minute></StopArrivalTime><StopPoint StopPointIdx="41587" StopPointId="39638" StopPointName="LA VILLETERTRE" StopPointExternalCode="DUA8738120" FareZone="100"><StopPointAddress StopPointAddressName="" StopPointAddressNumber="" StopPointAddressTypeName=""/><Equipment Sheltered="False" MIPAccess="False" Elevator="False" Escalator="False" BikeAccepted="False" BikeDepot="False"/><Mode ModeIdx="12" ModeId="12" ModeName="Train" ModeExternalCode="Train" ModeTypeExternalCode="RapidTransit"/><City CityIdx="1321" CityId="1295" CityName="Lavilletertre" CityExternalCode="60356" CityCode="60240"></City><StopArea StopAreaIdx="17825" StopAreaId="18698" StopAreaName="LA VILLETERTRE" StopAreaExternalCode="DUA8738120" MainStopArea="1" MultiModal="0" CarPark="0" MainConnection="0" AdditionalData="" ResaRailCode=""><Coord><CoordX>569663,00</CoordX><CoordY>2467290,00</CoordY></Coord></StopArea><Coord><CoordX>569663,00</CoordX><CoordY>2467290,00</CoordY></Coord></StopPoint></Stop><Stop StopIdx="7661292" StopPointIdx="41590" VehicleJourneyIdx="391578" HourNumber="0" MinuteNumber="0" DestinationPos="-1" ODTIdx="0" ODTPos="-1" ValidityPatternSetCommentPos="0" StopOrder="11" VehicleIdx="0"><StopTime><TotalSeconds>69720</TotalSeconds><Day>0</Day><Hour>19</Hour><Minute>22</Minute></StopTime><StopArrivalTime><TotalSeconds>69660</TotalSeconds><Day>0</Day><Hour>19</Hour><Minute>21</Minute></StopArrivalTime><StopPoint StopPointIdx="41590" StopPointId="39639" StopPointName="LIANCOURT SAINT-PIERRE" StopPointExternalCode="DUA8738121" FareZone="100"><StopPointAddress StopPointAddressName="" StopPointAddressNumber="" StopPointAddressTypeName=""/><Equipment Sheltered="False" MIPAccess="False" Elevator="False" Escalator="False" BikeAccepted="False" BikeDepot="False"/><Mode ModeIdx="12" ModeId="12" ModeName="Train" ModeExternalCode="Train" ModeTypeExternalCode="RapidTransit"/><City CityIdx="1323" CityId="1296" CityName="Liancourt-Saint-Pierre" CityExternalCode="60361" CityCode="60240"></City><StopArea StopAreaIdx="17827" StopAreaId="18700" StopAreaName="LIANCOURT SAINT-PIERRE" StopAreaExternalCode="DUA8738121" MainStopArea="1" MultiModal="0" CarPark="0" MainConnection="0" AdditionalData="" ResaRailCode=""><Coord><CoordX>568562,00</CoordX><CoordY>2469312,00</CoordY></Coord></StopArea><Coord><CoordX>568562,00</CoordX><CoordY>2469312,00</CoordY></Coord></StopPoint></Stop><Stop StopIdx="7721453" StopPointIdx="41555" VehicleJourneyIdx="391578" HourNumber="0" MinuteNumber="0" DestinationPos="-1" ODTIdx="0" ODTPos="-1" ValidityPatternSetCommentPos="0" StopOrder="12" VehicleIdx="0"><StopTime><TotalSeconds>70080</TotalSeconds><Day>0</Day><Hour>19</Hour><Minute>28</Minute></StopTime><StopArrivalTime><TotalSeconds>70080</TotalSeconds><Day>0</Day><Hour>19</Hour><Minute>28</Minute></StopArrivalTime><StopPoint StopPointIdx="41555" StopPointId="39640" StopPointName="CHAUMONT EN VEXIN" StopPointExternalCode="DUA8738122" FareZone="100"><StopPointAddress StopPointAddressName="" StopPointAddressNumber="" StopPointAddressTypeName=""/><Equipment Sheltered="False" MIPAccess="False" Elevator="False" Escalator="False" BikeAccepted="False" BikeDepot="False"/><Mode ModeIdx="12" ModeId="12" ModeName="Train" ModeExternalCode="Train" ModeTypeExternalCode="RapidTransit"/><City CityIdx="1307" CityId="1290" CityName="Chaumont-en-Vexin" CityExternalCode="60143" CityCode="60240"></City><StopArea StopAreaIdx="17804" StopAreaId="18677" StopAreaName="CHAUMONT EN VEXIN" StopAreaExternalCode="DUA8738122" MainStopArea="1" MultiModal="0" CarPark="0" MainConnection="0" AdditionalData="" ResaRailCode=""><Coord><CoordX>566204,00</CoordX><CoordY>2473835,00</CoordY></Coord></StopArea><Coord><CoordX>566204,00</CoordX><CoordY>2473835,00</CoordY></Coord></StopPoint></Stop><Stop StopIdx="7771163" StopPointIdx="41679" VehicleJourneyIdx="391578" HourNumber="0" MinuteNumber="0" DestinationPos="-1" ODTIdx="0" ODTPos="-1" ValidityPatternSetCommentPos="0" StopOrder="13" VehicleIdx="0"><StopTime><TotalSeconds>70380</TotalSeconds><Day>0</Day><Hour>19</Hour><Minute>33</Minute></StopTime><StopArrivalTime><TotalSeconds>70380</TotalSeconds><Day>0</Day><Hour>19</Hour><Minute>33</Minute></StopArrivalTime><StopPoint StopPointIdx="41679" StopPointId="39641" StopPointName="TRIE CHATEAU" StopPointExternalCode="DUA8738123" FareZone="100"><StopPointAddress StopPointAddressName="" StopPointAddressNumber="" StopPointAddressTypeName=""/><Equipment Sheltered="False" MIPAccess="False" Elevator="False" Escalator="False" BikeAccepted="False" BikeDepot="False"/><Mode ModeIdx="12" ModeId="12" ModeName="Train" ModeExternalCode="Train" ModeTypeExternalCode="RapidTransit"/><City CityIdx="1346" CityId="1305" CityName="Trie-Ch�teau" CityExternalCode="60644" CityCode="60590"></City><StopArea StopAreaIdx="17884" StopAreaId="18760" StopAreaName="TRIE CHATEAU" StopAreaExternalCode="DUA8738123" MainStopArea="1" MultiModal="0" CarPark="0" MainConnection="0" AdditionalData="" ResaRailCode=""><Coord><CoordX>562249,00</CoordX><CoordY>2476227,00</CoordY></Coord></StopArea><Coord><CoordX>562249,00</CoordX><CoordY>2476227,00</CoordY></Coord></StopPoint></Stop><Stop StopIdx="7800949" StopPointIdx="41725" VehicleJourneyIdx="391578" HourNumber="0" MinuteNumber="0" DestinationPos="-1" ODTIdx="0" ODTPos="-1" ValidityPatternSetCommentPos="0" StopOrder="14" VehicleIdx="0"><StopTime><TotalSeconds>70560</TotalSeconds><Day>0</Day><Hour>19</Hour><Minute>36</Minute></StopTime><StopArrivalTime><TotalSeconds>70560</TotalSeconds><Day>0</Day><Hour>19</Hour><Minute>36</Minute></StopArrivalTime><StopPoint StopPointIdx="41725" StopPointId="39642" StopPointName="GISORS" StopPointExternalCode="DUA8738124" FareZone="100"><StopPointAddress StopPointAddressName="" StopPointAddressNumber="" StopPointAddressTypeName=""/><Equipment Sheltered="False" MIPAccess="False" Elevator="False" Escalator="False" BikeAccepted="False" BikeDepot="False"/><Mode ModeIdx="12" ModeId="12" ModeName="Train" ModeExternalCode="Train" ModeTypeExternalCode="RapidTransit"/><City CityIdx="1360" CityId="1309" CityName="Gisors" CityExternalCode="27284" CityCode="27140"></City><StopArea StopAreaIdx="17907" StopAreaId="18785" StopAreaName="GISORS" StopAreaExternalCode="DUA8738124" MainStopArea="1" MultiModal="0" CarPark="0" MainConnection="0" AdditionalData="" ResaRailCode=""><Coord><CoordX>559847,00</CoordX><CoordY>2476541,00</CoordY></Coord></StopArea><Coord><CoordX>559847,00</CoordX><CoordY>2476541,00</CoordY></Coord></StopPoint></Stop></StopList></VehicleJourney></VehicleJourneyList><PagerInfo ResponseCount="1" ResponseStartIndex="0" TotalCount="1"/></ActionVehicleJourneyList>
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ raw_payload = %(
4
+
5
+ )
6
+
7
+ describe Transilien::MicroService do
8
+ it 'should get a set of Stop' do
9
+ # This payload was generated from
10
+ # http://ms.api.transilien.com/?action=VehicleJourneyList&RouteExternalCode=DUA8008540420003%3BDUA8008540430008%3BDUA8008540430010%3BDUA8008540430005%3BDUA8008544000030%3BDUA8008540440001|or&Date=2013|10|24&StartTime=18|19&EndTime=18|21
11
+ vj = Transilien::VehicleJourney.from_node(Nokogiri.XML((Pathname.new('spec') + 'vehicle_journey_alone.xml').read), Time.now)
12
+ vj.stops.first.class.should eql(Transilien::Stop)
13
+ end
14
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'transilien/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "transilien_microservices"
8
+ gem.version = Transilien::VERSION
9
+ gem.authors = ["Thomas Lecavelier"]
10
+ gem.email = ["thomas-gems@lecavelier.name"]
11
+ gem.description = %q{Implements SNCF Transilien micro-services API: enable access to their theoric offer.}
12
+ gem.summary = %q{See http://test.data-sncf.com/index.php?p=transilien}
13
+ gem.homepage = "https://github.com/ook/transilien_microservices"
14
+ gem.license = 'MIT'
15
+
16
+ gem.add_runtime_dependency('faraday', '>= 0.8.4') # HTTP(S) connections
17
+ gem.add_runtime_dependency('nokogiri', '>= 1.5.5') # XML parsing
18
+
19
+ gem.files = `git ls-files`.split($/)
20
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
21
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
22
+ gem.require_paths = ["lib"]
23
+ end
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: transilien_microservices
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Thomas Lecavelier
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.8.4
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.8.4
27
+ - !ruby/object:Gem::Dependency
28
+ name: nokogiri
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 1.5.5
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: 1.5.5
41
+ description: 'Implements SNCF Transilien micro-services API: enable access to their
42
+ theoric offer.'
43
+ email:
44
+ - thomas-gems@lecavelier.name
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - .gitignore
50
+ - .rspec
51
+ - .ruby-version
52
+ - Gemfile
53
+ - Gemfile.lock
54
+ - Guardfile
55
+ - LICENSE.txt
56
+ - README.md
57
+ - Rakefile
58
+ - lib/transilien/company.rb
59
+ - lib/transilien/line.rb
60
+ - lib/transilien/micro_service.rb
61
+ - lib/transilien/mode.rb
62
+ - lib/transilien/mode_type.rb
63
+ - lib/transilien/network.rb
64
+ - lib/transilien/route.rb
65
+ - lib/transilien/stop.rb
66
+ - lib/transilien/stop_area.rb
67
+ - lib/transilien/stop_point.rb
68
+ - lib/transilien/time.rb
69
+ - lib/transilien/vehicle_journey.rb
70
+ - lib/transilien/version.rb
71
+ - lib/transilien_microservices.rb
72
+ - spec/microservice_spec.rb
73
+ - spec/spec_helper.rb
74
+ - spec/vehicle_journey_alone.xml
75
+ - spec/vehicle_journey_spec.rb
76
+ - transilien_microservices.gemspec
77
+ homepage: https://github.com/ook/transilien_microservices
78
+ licenses:
79
+ - MIT
80
+ metadata: {}
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ requirements: []
96
+ rubyforge_project:
97
+ rubygems_version: 2.0.0
98
+ signing_key:
99
+ specification_version: 4
100
+ summary: See http://test.data-sncf.com/index.php?p=transilien
101
+ test_files:
102
+ - spec/microservice_spec.rb
103
+ - spec/spec_helper.rb
104
+ - spec/vehicle_journey_alone.xml
105
+ - spec/vehicle_journey_spec.rb
106
+ has_rdoc: