module GovauPtv
Constants
- STYLE_NICK
- STYLE_TITLE
Public Instance Methods
Source
# File lib/govau_ptv.rb, line 29 def build_url(path, devid:, key:, query: {}) sig = signature(path: path, devid: devid, key: key) params = query.merge(devid: devid, signature: sig) query_string = params.map { |k, v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" }.join("&") "#{GovauConfig::PTV_BASE}#{path}?#{query_string}" end
Source
# File lib/govau_ptv.rb, line 216 def delay_label(delay_sec) delay = delay_sec.to_i return "" if delay < 60 " (+#{delay / 60}m)" end
Source
# File lib/govau_ptv.rb, line 62 def fetch_departures(stop_id, devid:, key:, fetch: nil, max_results: GovauConfig::MAX_DEPARTURES) path = "/v3/departures/route_type/#{GovauConfig::ROUTE_TYPE_TRAIN}/stop/#{stop_id}" url = build_url( path, devid: devid, key: key, query: { max_results: max_results, expand: "true" } ) fetch_json(url, fetch: fetch) rescue StandardError {} end
Source
# File lib/govau_ptv.rb, line 75 def fetch_disruptions(devid:, key:, fetch: nil) path = "/v3/disruptions" url = build_url(path, devid: devid, key: key) fetch_json(url, fetch: fetch) rescue StandardError {} end
Source
# File lib/govau_ptv.rb, line 36 def fetch_json(url, fetch: nil) body = fetch ? fetch.call(url) : RabbotHttp.fetch(url) JSON.parse(body) end
Source
# File lib/govau_ptv.rb, line 83 def fetch_next_departures(station, devid:, key:, fetch: nil, max_results: GovauConfig::MAX_DEPARTURES) stop = find_train_stop(station, devid: devid, key: key, fetch: fetch) return [] unless stop payload = fetch_departures(stop[:stop_id], devid: devid, key: key, fetch: fetch, max_results: max_results) parse_departures(payload, stop_name: stop[:stop_name]) end
Source
# File lib/govau_ptv.rb, line 50 def find_train_stop(name, devid:, key:, fetch: nil) stops = search_stops(name, devid: devid, key: key, fetch: fetch) return nil if stops.empty? picked = stops.find { |stop| stop["stop_name"].to_s.match?(/station/i) } || stops.first { stop_id: picked["stop_id"], stop_name: picked["stop_name"], route_type: picked["route_type"] } end
Source
# File lib/govau_ptv.rb, line 223 def first_present(*values) values.each do |value| text = value.to_s.strip return text unless text.empty? end "" end
Source
# File lib/govau_ptv.rb, line 141 def format_departures(station, rows) title_station = station.to_s.strip lines = [ IrcFormat.report_header( tag: "GOVAU", title: "#{title_station} · metro train departures", style: STYLE_TITLE ) ] if rows.empty? lines << "No upcoming departures found." else rows.each do |row| time_label = format_local_time(row[:estimated_at] || row[:scheduled_at]) delay_note = delay_label(row[:delay_sec]) platform = row[:platform].empty? ? "" : " · Platform #{row[:platform]}" lines << "#{time_label} — #{row[:destination]}#{platform}#{delay_note}" end end lines << IrcFormat.report_footer("PTV Timetable API", "data.gov.au") lines.join("\n") end
Source
# File lib/govau_ptv.rb, line 166 def format_disruptions(rows, title: "Metro train disruptions", footer_label: nil) lines = [ IrcFormat.report_header(tag: "GOVAU", title: title, style: STYLE_TITLE) ] if rows.empty? lines << "No #{title.downcase} reported." else rows.first(GovauConfig::MAX_DISRUPTIONS).each do |row| lines << row[:title] lines << row[:description] unless row[:description].empty? end end active_label = footer_label || "#{rows.length} active" lines << IrcFormat.report_footer(active_label, "PTV · data.gov.au") lines.join("\n") end
Source
# File lib/govau_ptv.rb, line 206 def format_local_time(time) return "—" unless time melbourne = TZInfo::Timezone.get("Australia/Melbourne") local = melbourne.utc_to_local(time.utc) local.strftime("%H:%M") rescue StandardError time.utc.strftime("%H:%M") end
Source
# File lib/govau_ptv.rb, line 185 def format_stations(query, stops) count = stops.length meta = count.zero? ? query.to_s.strip : "#{query.to_s.strip} · #{count} stations" lines = [ IrcFormat.report_header(tag: "GOVAU", title: "Station search · #{meta}", style: STYLE_TITLE) ] if stops.empty? lines << "No matching stations found." else stops.first(GovauConfig::MAX_STATION_RESULTS).each do |stop| suburb = stop["stop_suburb"].to_s.strip suffix = suburb.empty? ? "" : " · #{suburb}" lines << "#{stop['stop_name']}#{suffix}" end end lines << IrcFormat.report_footer("PTV Timetable API", "data.gov.au") lines.join("\n") end
Source
# File lib/govau_ptv.rb, line 137 def on_time?(row, threshold: GovauConfig::DELAY_THRESHOLD_SEC) row[:delay_sec].to_i <= threshold end
Source
# File lib/govau_ptv.rb, line 91 def parse_departures(payload, stop_name: nil) routes = payload["routes"] || {} runs = payload["runs"] || {} disruptions = payload["disruptions"] || {} Array(payload["departures"]).map do |dep| route = routes[dep["route_id"].to_s] || {} run = runs[dep["run_id"].to_s] || {} scheduled = parse_time(dep["scheduled_departure_utc"]) estimated = parse_time(dep["estimated_departure_utc"]) || scheduled delay_sec = scheduled && estimated ? [estimated - scheduled, 0].max : 0 disruption_ids = Array(dep["disruption_ids"]) { stop_name: stop_name, destination: first_present(run["destination_name"], route["route_name"]), line: first_present(route["route_number"], route["route_name"]), platform: dep["platform_number"].to_s, scheduled_at: scheduled, estimated_at: estimated, delay_sec: delay_sec, disrupted: disruption_ids.any? || delay_sec > GovauConfig::DELAY_THRESHOLD_SEC } end end
Source
# File lib/govau_ptv.rb, line 117 def parse_disruptions(payload, status: "Current") entries = payload["disruptions"] rows = case entries when Hash then entries.values when Array then entries else [] end rows.filter_map do |row| next unless row.is_a?(Hash) next unless row["disruption_status"].to_s.casecmp(status).zero? { title: row["title"].to_s.strip, description: row["description"].to_s.gsub(/\s+/, " ").strip, status: row["disruption_status"].to_s } end end
Source
# File lib/govau_ptv.rb, line 231 def parse_time(value) return nil if value.nil? || value.to_s.strip.empty? Time.parse(value.to_s) rescue StandardError nil end
Source
# File lib/govau_ptv.rb, line 41 def search_stops(term, devid:, key:, fetch: nil, route_type: GovauConfig::ROUTE_TYPE_TRAIN) path = "/v3/search/#{CGI.escape(term.to_s.strip)}" url = build_url(path, devid: devid, key: key) payload = fetch_json(url, fetch: fetch) Array(payload["stops"]).select { |stop| stop["route_type"] == route_type } rescue StandardError [] end
Source
# File lib/govau_ptv.rb, line 24 def signature(path:, devid:, key:) request = "#{path}?devid=#{devid}" OpenSSL::HMAC.hexdigest("sha1", key.to_s, request).upcase end