aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/af83/decorator/link.rb10
-rw-r--r--lib/gtfs/time.rb28
-rw-r--r--lib/route_way_cost_unit_converter.rb14
-rw-r--r--lib/stif/netex_file.rb28
-rw-r--r--lib/tasks/ci.rake17
-rw-r--r--lib/tom_tom.rb4
-rw-r--r--lib/tom_tom/matrix.rb114
-rw-r--r--lib/tom_tom/matrix/point.rb18
-rw-r--r--lib/tom_tom/matrix/request_json_serializer.rb25
9 files changed, 235 insertions, 23 deletions
diff --git a/lib/af83/decorator/link.rb b/lib/af83/decorator/link.rb
index ee09f80dc..9bf6c1ed9 100644
--- a/lib/af83/decorator/link.rb
+++ b/lib/af83/decorator/link.rb
@@ -85,6 +85,10 @@ class AF83::Decorator::Link
in_group_for_action? :secondary
end
+ def disabled?
+ !!disabled
+ end
+
def enabled?
enabled = false
if @options[:_if].nil?
@@ -131,9 +135,9 @@ class AF83::Decorator::Link
out[:class] = extra_class
out.delete(:link_class)
out.delete(:link_method)
- out[:class] += " disabled" if disabled
+ out[:class] += " disabled" if disabled?
out[:class].strip!
- out[:disabled] = !!disabled
+ out[:disabled] = disabled?
out
end
@@ -150,7 +154,7 @@ class AF83::Decorator::Link
html_options
).to_html
else
- context.h.link_to content, href, html_options
+ context.h.link_to content, (disabled? ? "#" : href), html_options
end
end
end
diff --git a/lib/gtfs/time.rb b/lib/gtfs/time.rb
new file mode 100644
index 000000000..49546532a
--- /dev/null
+++ b/lib/gtfs/time.rb
@@ -0,0 +1,28 @@
+module GTFS
+ class Time
+ attr_reader :hours, :minutes, :seconds
+ def initialize(hours, minutes, seconds)
+ @hours, @minutes, @seconds = hours, minutes, seconds
+ end
+
+ def real_hours
+ hours.modulo(24)
+ end
+
+ def time
+ @time ||= ::Time.new(2000, 1, 1, real_hours, minutes, seconds, "+00:00")
+ end
+
+ def day_offset
+ hours / 24
+ end
+
+ FORMAT = /(\d{1,2}):(\d{2}):(\d{2})/
+
+ def self.parse(definition)
+ if definition.to_s =~ FORMAT
+ new *[$1, $2, $3].map(&:to_i)
+ end
+ end
+ end
+end
diff --git a/lib/route_way_cost_unit_converter.rb b/lib/route_way_cost_unit_converter.rb
index 45edbf538..52515e52c 100644
--- a/lib/route_way_cost_unit_converter.rb
+++ b/lib/route_way_cost_unit_converter.rb
@@ -8,18 +8,24 @@ class RouteWayCostUnitConverter
end
end
- private
-
# Round to 2 decimal places to appease JavaScript validation
def self.meters_to_kilometers(num)
return 0 unless num
- (num / 1000.0).to_i
+ snap_to_one(num / 1000.0).to_i
end
def self.seconds_to_minutes(num)
return 0 unless num
- num / 60
+ snap_to_one(num / 60.0).to_i
+ end
+
+ private
+
+ def self.snap_to_one(decimal)
+ return 1 if decimal > 0 && decimal <= 1
+
+ decimal
end
end
diff --git a/lib/stif/netex_file.rb b/lib/stif/netex_file.rb
index db0801bbe..1e78ca04a 100644
--- a/lib/stif/netex_file.rb
+++ b/lib/stif/netex_file.rb
@@ -47,6 +47,23 @@ module STIF
base_name = File.basename(file_name)
STIF::NetexFile::LINE_FILE_FORMAT.match(base_name).try(:[], 'line_object_id')
end
+
+ def parse_calendars calendars
+ # <netex:ValidBetween>
+ # <netex:FromDate>2017-03-01</netex:FromDate>
+ # <netex:ToDate>2017-03-31</netex:ToDate>
+ # </netex:ValidBetween>
+ xml = Nokogiri::XML(calendars)
+ from_date = nil
+ to_date = nil
+ xml.xpath("//netex:ValidBetween", "netex" => NetexFile::XML_NAME_SPACE).each do |valid_between|
+ from_date = valid_between.xpath("netex:FromDate").try :text
+ to_date = valid_between.xpath("netex:ToDate").try :text
+ end
+ from_date = from_date && Date.parse(from_date)
+ to_date = to_date && Date.parse(to_date)
+ Range.new from_date, to_date
+ end
end
attr_accessor :name
@@ -56,16 +73,7 @@ module STIF
end
def parse_calendars(calendars)
- # <netex:ValidBetween>
- # <netex:FromDate>2017-03-01</netex:FromDate>
- # <netex:ToDate>2017-03-31</netex:ToDate>
- # </netex:ValidBetween>
- xml = Nokogiri::XML(calendars)
- xml.xpath("//netex:ValidBetween", "netex" => NetexFile::XML_NAME_SPACE).each do |valid_between|
- from_date = valid_between.xpath("netex:FromDate").try :text
- to_date = valid_between.xpath("netex:ToDate").try :text
- periods << Range.new(Date.parse(from_date), Date.parse(to_date))
- end
+ periods << self.class.parse_calendars(calendars)
end
def add_offer_file(line_object_id)
diff --git a/lib/tasks/ci.rake b/lib/tasks/ci.rake
index 5b2c8ae3c..cb9ed77e7 100644
--- a/lib/tasks/ci.rake
+++ b/lib/tasks/ci.rake
@@ -10,6 +10,7 @@ namespace :ci do
desc "Prepare CI build"
task :setup do
+ cp "config/database.yml", "config/database.yml.orig"
cp "config/database/ci.yml", "config/database.yml"
puts "Use #{database_name} database"
sh "RAILS_ENV=test rake db:drop db:create db:migrate"
@@ -28,6 +29,7 @@ namespace :ci do
end
def deploy_env
+ return ENV["DEPLOY_ENV"] if ENV["DEPLOY_ENV"]
if git_branch == "master"
"dev"
elsif git_branch.in?(deploy_envs)
@@ -54,12 +56,12 @@ namespace :ci do
desc "Deploy after CI"
task :deploy do
- return if ENV["CHOUETTE_DEPLOY_DISABLED"]
-
- if deploy_env
- sh "cap #{deploy_env} deploy:migrations"
- else
- puts "No deploy for branch #{git_branch}"
+ unless ENV["CHOUETTE_DEPLOY_DISABLED"]
+ if deploy_env
+ sh "cap #{deploy_env} deploy:migrations deploy:seed"
+ else
+ puts "No deploy for branch #{git_branch}"
+ end
end
end
@@ -75,6 +77,9 @@ namespace :ci do
task :clean do
puts "Drop #{database_name} database"
sh "RAILS_ENV=test rake db:drop"
+
+ # Restore projet config/database.yml
+ # cp "config/database.yml.orig", "config/database.yml" if File.exists?("config/database.yml.orig")
end
end
diff --git a/lib/tom_tom.rb b/lib/tom_tom.rb
index a1a2bda43..fcebcc7ac 100644
--- a/lib/tom_tom.rb
+++ b/lib/tom_tom.rb
@@ -19,4 +19,8 @@ module TomTom
def self.batch(way_costs)
TomTom::Batch.new(@connection).batch(way_costs)
end
+
+ def self.matrix(way_costs)
+ TomTom::Matrix.new(@connection).matrix(way_costs)
+ end
end
diff --git a/lib/tom_tom/matrix.rb b/lib/tom_tom/matrix.rb
new file mode 100644
index 000000000..b0c8cc335
--- /dev/null
+++ b/lib/tom_tom/matrix.rb
@@ -0,0 +1,114 @@
+module TomTom
+ class Matrix
+ def initialize(connection)
+ @connection = connection
+ end
+
+ def matrix(way_costs)
+ points_with_ids = points_from_way_costs(way_costs)
+ points = points_as_params(points_with_ids)
+
+ Rails.logger.info "Invoke TomTom for #{points.size} points"
+
+ response = @connection.post do |req|
+ req.url '/routing/1/matrix/json'
+ req.headers['Content-Type'] = 'application/json'
+
+ req.params[:routeType] = 'shortest'
+ req.params[:travelMode] = 'bus'
+
+ req.body = build_request_body(points)
+ end
+
+ extract_costs_to_way_costs!(
+ way_costs,
+ points_with_ids,
+ JSON.parse(response.body)
+ )
+ end
+
+ def points_from_way_costs(way_costs)
+ points = []
+
+ way_costs.each do |way_cost|
+ departure_id, arrival_id = way_cost.id.split('-')
+
+ departure = TomTom::Matrix::Point.new(
+ way_cost.departure,
+ departure_id
+ )
+ arrival = TomTom::Matrix::Point.new(
+ way_cost.arrival,
+ arrival_id
+ )
+
+ # Don't add duplicate coordinates. This assumes that
+ # `way_costs` consists of an ordered route of points where
+ # each departure coordinate is the same as the preceding
+ # arrival coordinate.
+ if points.empty? ||
+ points.last.coordinates != departure.coordinates
+ points << departure
+ end
+
+ points << arrival
+ end
+
+ points
+ end
+
+ def points_as_params(points)
+ points.map do |point|
+ {
+ point: {
+ latitude: point.coordinates.lat,
+ longitude: point.coordinates.lng
+ }
+ }
+ end
+ end
+
+ def build_request_body(points)
+ # Serialize `BigDecimal` values as floats to please the TomTom API
+ RequestJSONSerializer.dump({
+ origins: points,
+ destinations: points
+ })
+ end
+
+ def extract_costs_to_way_costs!(way_costs, points, matrix_json)
+ way_costs = []
+
+ # `row` and `column` order is the same as `points`
+ matrix_json['matrix'].each_with_index do |row, row_i|
+ row.each_with_index do |column, column_i|
+ next if column['statusCode'] != 200
+
+ distance = column['response']['routeSummary']['lengthInMeters']
+
+ # Ignore costs between a point and itself (e.g. from A to A)
+ next if distance == 0
+
+ departure = points[row_i]
+ arrival = points[column_i]
+
+ way_costs << WayCost.new(
+ departure: Geokit::LatLng.new(
+ departure.coordinates.lat,
+ departure.coordinates.lng
+ ),
+ arrival: Geokit::LatLng.new(
+ arrival.coordinates.lat,
+ arrival.coordinates.lng
+ ),
+ distance: distance,
+ time: column['response']['routeSummary']['travelTimeInSeconds'],
+ id: "#{departure.id}-#{arrival.id}"
+ )
+ end
+ end
+
+ way_costs
+ end
+ end
+end
diff --git a/lib/tom_tom/matrix/point.rb b/lib/tom_tom/matrix/point.rb
new file mode 100644
index 000000000..435b4d4b0
--- /dev/null
+++ b/lib/tom_tom/matrix/point.rb
@@ -0,0 +1,18 @@
+module TomTom
+ class Matrix
+ class Point
+ attr_reader :coordinates, :id
+
+ def initialize(coordinates, id)
+ @coordinates = coordinates
+ @id = id
+ end
+
+ def ==(other)
+ other.is_a?(self.class) &&
+ @coordinates == other.coordinates &&
+ @id == other.id
+ end
+ end
+ end
+end
diff --git a/lib/tom_tom/matrix/request_json_serializer.rb b/lib/tom_tom/matrix/request_json_serializer.rb
new file mode 100644
index 000000000..f4d12e482
--- /dev/null
+++ b/lib/tom_tom/matrix/request_json_serializer.rb
@@ -0,0 +1,25 @@
+module TomTom
+ class Matrix
+ class RequestJSONSerializer
+ def self.dump(hash)
+ hash[:origins].map! do |point|
+ point_to_f(point)
+ end
+ hash[:destinations].map! do |point|
+ point_to_f(point)
+ end
+
+ JSON.dump(hash)
+ end
+
+ private
+
+ def self.point_to_f(point)
+ point[:point][:latitude] = point[:point][:latitude].to_f
+ point[:point][:longitude] = point[:point][:longitude].to_f
+
+ point
+ end
+ end
+ end
+end