Created
July 9, 2014 14:59
-
-
Save Val/09e43b3c4bd16a66071d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# -*- mode:ruby;tab-width:2;indent-tabs-mode:nil;coding:utf-8 -*- | |
# vim: ft=ruby syn=ruby fileencoding=utf-8 sw=2 ts=2 ai eol et si | |
# | |
# next_train_for.rb: french trains station in motion service client script | |
# (c) 2010-2014 Laurent Vallar <[email protected]>, WTFPL license v2 see below. | |
# | |
# This program is free software. It comes without any warranty, to | |
# the extent permitted by applicable law. You can redistribute it | |
# and/or modify it under the terms of the Do What The Fuck You Want | |
# To Public License, Version 2, as published by Sam Hocevar. See | |
# http://www.wtfpl.net/ for more details. | |
DEFAULT = 'Epinal' # default station | |
BASE_URL = 'http://www.gares-en-mouvement.com/fr/' # station in motion base url | |
STATUS = 'dep' # (dep)artures / (arr)ivals | |
gem 'mechanize' | |
require 'mechanize' | |
# get station name from command line if any | |
station = ARGV.length >= 1 ? ARGV[0].downcase.capitalize : DEFAULT | |
# get status (departures/arrivals) from command line if any | |
status = ARGV.length == 2 ? ARGV[1].downcase[0..2] : STATUS | |
# usage / help if needed | |
if ARGV == %w[ --help ] | |
STDERR.puts <<-EOF | |
#{$0} [city] [status] | |
where: | |
city is the city name, default: #{DEFAULT} | |
status is the ((arr)ivals|(dep)artures) list, default #{STATUS} | |
examples: | |
#{$0} 'Paris Est' arr | |
EOF | |
station = 'Paris Est' | |
status = 'arr' | |
end | |
# start Mechanize agent on main page to get station key | |
station_key = station_name = nil | |
agent = Mechanize.new | |
agent.get(BASE_URL) do |page| | |
page.links.each do |link| | |
station_name = link.text | |
if station_name =~ /#{station}/i && link.href =~ %r{/fr/(\w+)/accueil/$} | |
station_key = $1; break | |
end | |
end | |
end | |
headers = nil # store fields names as keys, titles as values | |
schedules = [] # store each schedule item as array of hashtables with | |
# same fields keys | |
# process schedule page and store all schedule items | |
agent.get("#{BASE_URL}#{station_key}/horaires-temps-reel/#{status}/") do |page| | |
# find shedule's DOM tree | |
schedules_doc = page.parser/'div[@class=infostempsreel_tgda]' | |
headers = Hash[*(schedules_doc/'thead/tr/th').map do |element| | |
key = element.attributes['id'].value.gsub(/_id$/, '').to_sym | |
key = :type if key == :marque_transporteur | |
[ key, element.inner_text ] | |
end.flatten] | |
# find schedule's entries | |
(schedules_doc/'tbody/tr').each do |element| # process table headers | |
schedule = {} | |
(element/'td').each do |sub_element| # find fields names | |
key = sub_element.attributes['class'].value.gsub(/^tvs_td_/, '').to_sym | |
next if sub_element.search('img').size > 0 | |
schedule[key] = sub_element.inner_text | |
end # then add schedule to schedule array (preserve order) | |
schedules << schedule unless schedule.values.all? { |v| v.length > 0 } | |
end | |
end # all done | |
print_array = [] # store schedules values in a flat array, YxX | |
ORDER = [ :type, :numero, :heure, :originedestination, :voie, :situation ] | |
ORDER.each do |x| # headers on first colon, then items values each colon. | |
print_array << headers[x] | |
schedules.each { |sched| print_array << (sched[x].nil? ? '' : sched[x]) } | |
end | |
b = print_array.each_slice(schedules.size + 1).to_a # sub arrays mark lines | |
def tabulate(a) # magic helper :) | |
a[0].zip(a.length > 2 ? tabulate(a[1..-1]) : a[-1]) | |
end | |
vcols = tabulate(b).map{|x| x.flatten.map {|x| x ? x : ''}} # magic (2) | |
widths = b.map{|x|x.max_by(&:length).length} # array of colons widths | |
buffer = vcols.map do |x| # magic (3) create buffer | |
' ' + x.each_with_index.map {|y,i| y.ljust(widths[i] + 2)}.join('| ') | |
end # then create header raw | |
hr = '-' + widths.map { |w| '-' * w }.map { |s| '--' + s }.join('+-') + '-' | |
puts "#{station_name} - #{status == 'dep' ? 'departures' : 'arrivals'}\n#{hr}" | |
puts buffer.join("\n").sub("\n", "\n" + hr + "\n") + "\n#{hr}" # add header raw |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment