gtfs-realtime 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -2
- data/bin/console +2 -1
- data/gtfs-realtime.gemspec +2 -1
- data/lib/gtfs/realtime.rb +180 -1
- data/lib/gtfs/realtime/calendar_date.rb +1 -1
- data/lib/gtfs/realtime/configuration.rb +8 -9
- data/lib/gtfs/realtime/migrations/001_create_gtfs_tables.rb +81 -0
- data/lib/gtfs/realtime/model.rb +8 -0
- data/lib/gtfs/realtime/service_alert.rb +1 -1
- data/lib/gtfs/realtime/shape.rb +1 -8
- data/lib/gtfs/realtime/stop.rb +8 -16
- data/lib/gtfs/realtime/stop_time.rb +4 -4
- data/lib/gtfs/realtime/stop_time_update.rb +12 -4
- data/lib/gtfs/realtime/trip.rb +6 -6
- data/lib/gtfs/realtime/trip_update.rb +2 -2
- data/lib/gtfs/realtime/vehicle_position.rb +2 -2
- data/lib/gtfs/realtime/version.rb +1 -1
- metadata +19 -5
- data/lib/gtfs/realtime/bootstrap.rb +0 -178
- data/lib/gtfs/realtime/database.rb +0 -140
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c4fb01e9aa3b3d57def85c0ebdbda36acbc4c9ab
|
4
|
+
data.tar.gz: d3bbf13907cd3b09a0e55cada1aa16dae4ec09c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bfc85354de0492acac1c60bf85a1d9085b170f502f57b3f32364b06eaa8fca59237bfee4f51b00e8ea8cac52a6d49ccce18ac90f1724aa1cbad80e106276934c
|
7
|
+
data.tar.gz: ff2b51ad9471a0f11ca788363f8968446504625b6f5a0538302dbe362d37e7954705014c5f8373d4c366f9dbb683d14a68418bc03f9fd2755a308e9d95288003
|
data/README.md
CHANGED
@@ -30,14 +30,16 @@ GTFS::Realtime.configure do |config|
|
|
30
30
|
config.trip_updates_feed = "http://realtime.ripta.com:81/api/tripupdates"
|
31
31
|
config.vehicle_positions_feed = "http://realtime.ripta.com:81/api/vehiclepositions"
|
32
32
|
config.service_alerts_feed = "http://realtime.ripta.com:81/api/servicealerts"
|
33
|
-
config.
|
33
|
+
config.database_url = "sqlite3:////Users/rofreg/database.db"
|
34
|
+
# leave database_url unset to use your existing ActiveRecord DB, or
|
35
|
+
# set it to `nil` to use an in-memory SQLite database
|
34
36
|
end
|
35
37
|
|
36
38
|
# After calling 'configure', the gem loads all relevant GTFS info into a database.
|
37
39
|
# This may take some time (up to a minute) depending on the size of the input data.
|
38
40
|
# By default, gtfs-realtime uses an in-memory database, which requires reloading all
|
39
41
|
# data from scratch on each launch. If you'd like to use a persistent database instead,
|
40
|
-
# set 'config.
|
42
|
+
# set 'config.database_url' above, and include a scheme/protocol path for the DB type
|
41
43
|
# that you would like to use. gtfs-realtime will generate the relevant tables.
|
42
44
|
|
43
45
|
@nearby = GTFS::Realtime::Stop.nearby(41.834521, -71.396906)
|
data/bin/console
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require "bundler/setup"
|
4
4
|
require "gtfs/realtime"
|
5
5
|
require "sqlite3"
|
6
|
+
require "uri"
|
6
7
|
|
7
8
|
# Load the RIPTA feed as an example, with a sqlite3 database
|
8
9
|
GTFS::Realtime.configure do |config|
|
@@ -10,7 +11,7 @@ GTFS::Realtime.configure do |config|
|
|
10
11
|
config.trip_updates_feed = "http://realtime.ripta.com:81/api/tripupdates"
|
11
12
|
config.vehicle_positions_feed = "http://realtime.ripta.com:81/api/vehiclepositions"
|
12
13
|
config.service_alerts_feed = "http://realtime.ripta.com:81/api/servicealerts"
|
13
|
-
config.
|
14
|
+
config.database_url = "sqlite3:///#{URI.escape(File.expand_path("../../database.db", __FILE__))}"
|
14
15
|
end
|
15
16
|
|
16
17
|
def reload!
|
data/gtfs-realtime.gemspec
CHANGED
data/lib/gtfs/realtime.rb
CHANGED
@@ -1,8 +1,22 @@
|
|
1
1
|
require "google/transit/gtfs-realtime.pb"
|
2
2
|
require "gtfs"
|
3
|
-
require "
|
3
|
+
require "active_record"
|
4
|
+
require "bulk_insert"
|
5
|
+
require "gtfs/gtfs_gem_patch"
|
4
6
|
|
5
7
|
require "gtfs/realtime/configuration"
|
8
|
+
require "gtfs/realtime/model"
|
9
|
+
require "gtfs/realtime/calendar_date"
|
10
|
+
require "gtfs/realtime/route"
|
11
|
+
require "gtfs/realtime/service_alert"
|
12
|
+
require "gtfs/realtime/shape"
|
13
|
+
require "gtfs/realtime/stop"
|
14
|
+
require "gtfs/realtime/stop_time"
|
15
|
+
require "gtfs/realtime/stop_time_update"
|
16
|
+
require "gtfs/realtime/trip"
|
17
|
+
require "gtfs/realtime/trip_update"
|
18
|
+
require "gtfs/realtime/vehicle_position"
|
19
|
+
require "gtfs/realtime/version"
|
6
20
|
|
7
21
|
module GTFS
|
8
22
|
class Realtime
|
@@ -17,9 +31,174 @@ module GTFS
|
|
17
31
|
def configure
|
18
32
|
yield(configuration)
|
19
33
|
|
34
|
+
run_migrations
|
20
35
|
load_static_feed!
|
21
36
|
refresh_realtime_feed!
|
22
37
|
end
|
38
|
+
|
39
|
+
def load_static_feed!(force: false)
|
40
|
+
return if !force && GTFS::Realtime::Route.count > 0
|
41
|
+
|
42
|
+
static_data = GTFS::Source.build(@configuration.static_feed)
|
43
|
+
return unless static_data
|
44
|
+
|
45
|
+
GTFS::Realtime::Model.transaction do
|
46
|
+
GTFS::Realtime::CalendarDate.delete_all
|
47
|
+
GTFS::Realtime::CalendarDate.bulk_insert(values:
|
48
|
+
static_data.calendar_dates.collect do |calendar_date|
|
49
|
+
{
|
50
|
+
service_id: calendar_date.service_id.strip,
|
51
|
+
date: Date.strptime(calendar_date.date, "%Y%m%d"),
|
52
|
+
exception_type: calendar_date.exception_type
|
53
|
+
}
|
54
|
+
end
|
55
|
+
)
|
56
|
+
|
57
|
+
GTFS::Realtime::Route.delete_all
|
58
|
+
GTFS::Realtime::Route.bulk_insert(:id, :short_name, :long_name, :url, values:
|
59
|
+
static_data.routes.collect do |route|
|
60
|
+
{
|
61
|
+
id: route.id.strip,
|
62
|
+
short_name: route.short_name,
|
63
|
+
long_name: route.long_name,
|
64
|
+
url: route.url
|
65
|
+
}
|
66
|
+
end
|
67
|
+
)
|
68
|
+
|
69
|
+
GTFS::Realtime::Shape.delete_all
|
70
|
+
GTFS::Realtime::Shape.bulk_insert(:id, :sequence, :latitude, :longitude, values:
|
71
|
+
static_data.shapes.collect do |shape|
|
72
|
+
{
|
73
|
+
id: shape.id.strip,
|
74
|
+
sequence: shape.pt_sequence,
|
75
|
+
latitude: shape.pt_lat.to_f,
|
76
|
+
longitude: shape.pt_lon.to_f
|
77
|
+
}
|
78
|
+
end
|
79
|
+
)
|
80
|
+
|
81
|
+
GTFS::Realtime::Stop.delete_all
|
82
|
+
GTFS::Realtime::Stop.bulk_insert(:id, :name, :latitude, :longitude, values:
|
83
|
+
static_data.stops.collect do |stop|
|
84
|
+
{
|
85
|
+
id: stop.id.strip,
|
86
|
+
name: stop.name.strip,
|
87
|
+
latitude: stop.lat.to_f,
|
88
|
+
longitude: stop.lon.to_f
|
89
|
+
}
|
90
|
+
end
|
91
|
+
)
|
92
|
+
|
93
|
+
GTFS::Realtime::StopTime.delete_all
|
94
|
+
GTFS::Realtime::StopTime.bulk_insert(values:
|
95
|
+
static_data.stop_times.collect do |stop_time|
|
96
|
+
{
|
97
|
+
stop_id: stop_time.stop_id.strip,
|
98
|
+
trip_id: stop_time.trip_id.strip,
|
99
|
+
arrival_time: stop_time.arrival_time,
|
100
|
+
departure_time: stop_time.departure_time,
|
101
|
+
stop_sequence: stop_time.stop_sequence.to_i
|
102
|
+
}
|
103
|
+
end
|
104
|
+
)
|
105
|
+
|
106
|
+
GTFS::Realtime::Trip.delete_all
|
107
|
+
GTFS::Realtime::Trip.bulk_insert(:id, :headsign, :route_id, :service_id, :shape_id, :direction_id, values:
|
108
|
+
static_data.trips.collect do |trip|
|
109
|
+
{
|
110
|
+
id: trip.id.strip,
|
111
|
+
headsign: trip.headsign.strip,
|
112
|
+
route_id: trip.route_id.strip,
|
113
|
+
service_id: trip.service_id.strip,
|
114
|
+
shape_id: trip.shape_id.strip,
|
115
|
+
direction_id: trip.direction_id
|
116
|
+
}
|
117
|
+
end
|
118
|
+
)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def refresh_realtime_feed!
|
123
|
+
trip_updates = get_entities(@configuration.trip_updates_feed)
|
124
|
+
vehicle_positions = get_entities(@configuration.vehicle_positions_feed)
|
125
|
+
service_alerts = get_entities(@configuration.service_alerts_feed)
|
126
|
+
|
127
|
+
GTFS::Realtime::Model.transaction do
|
128
|
+
GTFS::Realtime::TripUpdate.delete_all
|
129
|
+
GTFS::Realtime::TripUpdate.bulk_insert(:id, :trip_id, :route_id, values:
|
130
|
+
trip_updates.collect do |trip_update|
|
131
|
+
{
|
132
|
+
id: trip_update.id.strip,
|
133
|
+
trip_id: trip_update.trip_update.trip.trip_id.strip,
|
134
|
+
route_id: trip_update.trip_update.trip.route_id.strip
|
135
|
+
}
|
136
|
+
end
|
137
|
+
)
|
138
|
+
|
139
|
+
GTFS::Realtime::StopTimeUpdate.delete_all
|
140
|
+
GTFS::Realtime::StopTimeUpdate.bulk_insert(values:
|
141
|
+
trip_updates.collect do |trip_update|
|
142
|
+
trip_update.trip_update.stop_time_update.collect do |stop_time_update|
|
143
|
+
{
|
144
|
+
trip_update_id: trip_update.id.strip,
|
145
|
+
stop_id: stop_time_update.stop_id.strip,
|
146
|
+
arrival_delay: stop_time_update.arrival ? stop_time_update.arrival.delay : nil,
|
147
|
+
arrival_time: stop_time_update.arrival ? Time.at(stop_time_update.arrival.time) : nil,
|
148
|
+
departure_delay: stop_time_update.departure ? stop_time_update.departure.delay : nil,
|
149
|
+
departure_time: stop_time_update.departure ? Time.at(stop_time_update.departure.time) : nil,
|
150
|
+
}
|
151
|
+
end
|
152
|
+
end.flatten
|
153
|
+
)
|
154
|
+
|
155
|
+
GTFS::Realtime::VehiclePosition.delete_all
|
156
|
+
GTFS::Realtime::VehiclePosition.bulk_insert(values:
|
157
|
+
vehicle_positions.collect do |vehicle|
|
158
|
+
{
|
159
|
+
trip_id: vehicle.vehicle.trip.trip_id.strip,
|
160
|
+
stop_id: vehicle.vehicle.stop_id.strip,
|
161
|
+
latitude: vehicle.vehicle.position.latitude.to_f,
|
162
|
+
longitude: vehicle.vehicle.position.longitude.to_f,
|
163
|
+
bearing: vehicle.vehicle.position.bearing.to_f,
|
164
|
+
timestamp: Time.at(vehicle.vehicle.timestamp)
|
165
|
+
}
|
166
|
+
end
|
167
|
+
)
|
168
|
+
|
169
|
+
GTFS::Realtime::ServiceAlert.delete_all
|
170
|
+
GTFS::Realtime::ServiceAlert.bulk_insert(values:
|
171
|
+
service_alerts.collect do |service_alert|
|
172
|
+
{
|
173
|
+
stop_id: service_alert.alert.informed_entity.first.stop_id.strip,
|
174
|
+
header_text: service_alert.alert.header_text.translation.first.text,
|
175
|
+
description_text: service_alert.alert.description_text.translation.first.text,
|
176
|
+
start_time: Time.at(service_alert.alert.active_period.first.start),
|
177
|
+
end_time: Time.at(service_alert.alert.active_period.first.end)
|
178
|
+
}
|
179
|
+
end
|
180
|
+
)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
private
|
185
|
+
|
186
|
+
def get_entities(path)
|
187
|
+
return [] if path.nil?
|
188
|
+
|
189
|
+
if File.exists?(path)
|
190
|
+
data = File.open(path, 'r'){|f| f.read}
|
191
|
+
else
|
192
|
+
data = Net::HTTP.get(URI.parse(path))
|
193
|
+
end
|
194
|
+
feed = Transit_realtime::FeedMessage.decode(data)
|
195
|
+
feed.entity # array of entities
|
196
|
+
end
|
197
|
+
|
198
|
+
def run_migrations
|
199
|
+
ActiveRecord::Migration.verbose = false
|
200
|
+
ActiveRecord::Migrator.migrate(File.expand_path("../realtime/migrations", __FILE__))
|
201
|
+
end
|
23
202
|
end
|
24
203
|
end
|
25
204
|
end
|
@@ -1,17 +1,16 @@
|
|
1
1
|
module GTFS
|
2
2
|
class Realtime
|
3
3
|
class Configuration
|
4
|
-
attr_accessor :static_feed, :trip_updates_feed, :vehicle_positions_feed, :service_alerts_feed, :
|
4
|
+
attr_accessor :static_feed, :trip_updates_feed, :vehicle_positions_feed, :service_alerts_feed, :database_url
|
5
5
|
|
6
|
-
def
|
7
|
-
@
|
6
|
+
def database_url=(new_path)
|
7
|
+
@database_url = new_path
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
require 'gtfs/realtime/bootstrap'
|
9
|
+
if @database_url
|
10
|
+
ActiveRecord::Base.establish_connection(@database_url)
|
11
|
+
else
|
12
|
+
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
|
13
|
+
end
|
15
14
|
end
|
16
15
|
end
|
17
16
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
class CreateGtfsTables < ActiveRecord::Migration[5.0]
|
2
|
+
def change
|
3
|
+
create_table :gtfs_realtime_calendar_dates, id: false do |t|
|
4
|
+
t.string :service_id, index: true
|
5
|
+
t.date :date
|
6
|
+
t.integer :exception_type
|
7
|
+
end
|
8
|
+
|
9
|
+
create_table :gtfs_realtime_routes do |t|
|
10
|
+
t.string :short_name
|
11
|
+
t.string :long_name
|
12
|
+
t.string :url
|
13
|
+
end
|
14
|
+
change_column :gtfs_realtime_routes, :id, :string
|
15
|
+
|
16
|
+
create_table :gtfs_realtime_shapes, id: false do |t|
|
17
|
+
t.string :id # NOT unique
|
18
|
+
t.integer :sequence
|
19
|
+
t.float :latitude
|
20
|
+
t.float :longitude
|
21
|
+
|
22
|
+
t.index [:id, :sequence]
|
23
|
+
end
|
24
|
+
|
25
|
+
create_table :gtfs_realtime_stops do |t|
|
26
|
+
t.string :name
|
27
|
+
t.float :latitude
|
28
|
+
t.float :longitude
|
29
|
+
end
|
30
|
+
change_column :gtfs_realtime_stops, :id, :string
|
31
|
+
|
32
|
+
create_table :gtfs_realtime_stop_times, id: false do |t|
|
33
|
+
t.string :trip_id, index: true
|
34
|
+
t.string :stop_id, index: true
|
35
|
+
t.string :arrival_time
|
36
|
+
t.string :departure_time
|
37
|
+
t.integer :stop_sequence
|
38
|
+
end
|
39
|
+
|
40
|
+
create_table :gtfs_realtime_trips do |t|
|
41
|
+
t.string :headsign
|
42
|
+
t.string :route_id, index: true
|
43
|
+
t.string :service_id
|
44
|
+
t.string :shape_id
|
45
|
+
t.integer :direction_id
|
46
|
+
end
|
47
|
+
change_column :gtfs_realtime_trips, :id, :string
|
48
|
+
|
49
|
+
create_table :gtfs_realtime_trip_updates do |t|
|
50
|
+
t.string :trip_id
|
51
|
+
t.string :route_id
|
52
|
+
end
|
53
|
+
change_column :gtfs_realtime_trip_updates, :id, :string
|
54
|
+
|
55
|
+
create_table :gtfs_realtime_stop_time_updates, id: false do |t|
|
56
|
+
t.string :trip_update_id, index: true
|
57
|
+
t.string :stop_id, index: true
|
58
|
+
t.integer :arrival_delay
|
59
|
+
t.timestamp :arrival_time
|
60
|
+
t.integer :departure_delay
|
61
|
+
t.timestamp :departure_time
|
62
|
+
end
|
63
|
+
|
64
|
+
create_table :gtfs_realtime_vehicle_positions, id: false do |t|
|
65
|
+
t.string :trip_id, index: true
|
66
|
+
t.string :stop_id, index: true
|
67
|
+
t.float :latitude
|
68
|
+
t.float :longitude
|
69
|
+
t.float :bearing
|
70
|
+
t.timestamp :timestamp
|
71
|
+
end
|
72
|
+
|
73
|
+
create_table :gtfs_realtime_service_alerts, id: false do |t|
|
74
|
+
t.string :stop_id, index: true
|
75
|
+
t.string :header_text
|
76
|
+
t.text :description_text
|
77
|
+
t.timestamp :start_time
|
78
|
+
t.timestamp :end_time
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/gtfs/realtime/shape.rb
CHANGED
@@ -1,14 +1,7 @@
|
|
1
1
|
module GTFS
|
2
2
|
class Realtime
|
3
3
|
class Shape < GTFS::Realtime::Model
|
4
|
-
|
5
|
-
def ordered_by_sequence
|
6
|
-
order(:sequence)
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
# order results by sequence by default
|
11
|
-
set_dataset(self.ordered_by_sequence)
|
4
|
+
scope :ordered, -> { order(sequence: :ASC) }
|
12
5
|
end
|
13
6
|
end
|
14
7
|
end
|
data/lib/gtfs/realtime/stop.rb
CHANGED
@@ -5,24 +5,16 @@ module GTFS
|
|
5
5
|
class Stop < GTFS::Realtime::Model
|
6
6
|
include GTFS::Realtime::Nearby
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
[:trips, :id, :route_id]
|
16
|
-
]
|
17
|
-
many_through_many :active_routes, class: GTFS::Realtime::Route, through: [
|
18
|
-
[:stop_time_updates, :stop_id, :trip_update_id],
|
19
|
-
[:trip_updates, :id, :route_id]
|
20
|
-
]
|
8
|
+
has_many :service_alerts
|
9
|
+
has_many :stop_times
|
10
|
+
has_many :stop_time_updates
|
11
|
+
has_many :trips, through: :stop_times
|
12
|
+
has_many :trip_updates, through: :stop_times
|
13
|
+
has_many :routes, through: :trips
|
14
|
+
has_many :active_routes, through: :trip_updates, source: :route
|
21
15
|
|
22
16
|
def stop_times_schedule_for(date)
|
23
|
-
|
24
|
-
self_with_eager_loads = GTFS::Realtime::Stop.where(id: id).eager(stop_times: {trip: [:calendar_dates, :route, :shapes]}).all.first
|
25
|
-
self_with_eager_loads.stop_times.select{|st| st.trip.active?(Date.today)}.sort_by{|st| st.departure_time}
|
17
|
+
stop_times.includes(trip: [:calendar_dates, :route, :shapes]).select{|st| st.trip.active?(date)}.sort_by{|st| st.departure_time}
|
26
18
|
end
|
27
19
|
|
28
20
|
def stop_times_for_today
|
@@ -1,8 +1,9 @@
|
|
1
1
|
module GTFS
|
2
2
|
class Realtime
|
3
3
|
class StopTime < GTFS::Realtime::Model
|
4
|
-
|
5
|
-
|
4
|
+
belongs_to :trip
|
5
|
+
belongs_to :trip_update, primary_key: :trip_id, foreign_key: :trip_id
|
6
|
+
belongs_to :stop
|
6
7
|
|
7
8
|
attr_accessor :actual_arrival_time, :actual_arrival_delay, :actual_departure_time, :actual_departure_delay
|
8
9
|
|
@@ -38,7 +39,6 @@ module GTFS
|
|
38
39
|
private
|
39
40
|
|
40
41
|
def self.parse_time(time, date = Date.today)
|
41
|
-
# TODO: handle case where date != Date.today
|
42
42
|
day_adjustment = 0
|
43
43
|
hour = time[0...2].to_i
|
44
44
|
|
@@ -48,7 +48,7 @@ module GTFS
|
|
48
48
|
time[0...2] = (hour % 24).to_s.rjust(2, '0')
|
49
49
|
end
|
50
50
|
|
51
|
-
Time.parse(time) + day_adjustment * 60 * 60 * 24
|
51
|
+
Time.parse("#{date} #{time}").in_time_zone(Time.zone) + day_adjustment * 60 * 60 * 24
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
@@ -1,10 +1,18 @@
|
|
1
1
|
module GTFS
|
2
2
|
class Realtime
|
3
3
|
class StopTimeUpdate < GTFS::Realtime::Model
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
belongs_to :stop
|
5
|
+
belongs_to :trip_update
|
6
|
+
has_one :trip, through: :trip_update
|
7
|
+
has_one :route, through: :trip_update
|
8
|
+
|
9
|
+
def arrival_time
|
10
|
+
super ? super.in_time_zone(Time.zone) : nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def departure_time
|
14
|
+
super ? super.in_time_zone(Time.zone) : nil
|
15
|
+
end
|
8
16
|
end
|
9
17
|
end
|
10
18
|
end
|
data/lib/gtfs/realtime/trip.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
module GTFS
|
2
2
|
class Realtime
|
3
3
|
class Trip < GTFS::Realtime::Model
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
belongs_to :route
|
5
|
+
has_many :stop_times
|
6
|
+
has_many :stops, through: :stop_times
|
7
|
+
has_many :calendar_dates, primary_key: :service_id, foreign_key: :service_id
|
8
|
+
has_many :shapes, primary_key: :shape_id, foreign_key: :id
|
8
9
|
|
9
10
|
def active?(date)
|
10
|
-
|
11
|
-
calendar_dates.find{|cd| cd.exception_type == GTFS::Realtime::CalendarDate::ADDED && cd.date == date}
|
11
|
+
calendar_dates.where(exception_type: GTFS::Realtime::CalendarDate::ADDED, date: date).any?
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gtfs-realtime
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Laughlin
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-12-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -109,7 +109,21 @@ dependencies:
|
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
112
|
+
name: activerecord
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: bulk_insert
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
114
128
|
requirements:
|
115
129
|
- - ">="
|
@@ -143,10 +157,10 @@ files:
|
|
143
157
|
- gtfs-realtime.gemspec
|
144
158
|
- lib/gtfs/gtfs_gem_patch.rb
|
145
159
|
- lib/gtfs/realtime.rb
|
146
|
-
- lib/gtfs/realtime/bootstrap.rb
|
147
160
|
- lib/gtfs/realtime/calendar_date.rb
|
148
161
|
- lib/gtfs/realtime/configuration.rb
|
149
|
-
- lib/gtfs/realtime/
|
162
|
+
- lib/gtfs/realtime/migrations/001_create_gtfs_tables.rb
|
163
|
+
- lib/gtfs/realtime/model.rb
|
150
164
|
- lib/gtfs/realtime/nearby.rb
|
151
165
|
- lib/gtfs/realtime/route.rb
|
152
166
|
- lib/gtfs/realtime/service_alert.rb
|
@@ -1,178 +0,0 @@
|
|
1
|
-
require "gtfs/gtfs_gem_patch"
|
2
|
-
require "gtfs/realtime/calendar_date"
|
3
|
-
require "gtfs/realtime/route"
|
4
|
-
require "gtfs/realtime/service_alert"
|
5
|
-
require "gtfs/realtime/shape"
|
6
|
-
require "gtfs/realtime/stop"
|
7
|
-
require "gtfs/realtime/stop_time"
|
8
|
-
require "gtfs/realtime/stop_time_update"
|
9
|
-
require "gtfs/realtime/trip"
|
10
|
-
require "gtfs/realtime/trip_update"
|
11
|
-
require "gtfs/realtime/vehicle_position"
|
12
|
-
require "gtfs/realtime/version"
|
13
|
-
|
14
|
-
module GTFS
|
15
|
-
class Realtime
|
16
|
-
# This is a singleton object, so everything will be on the class level
|
17
|
-
class << self
|
18
|
-
def load_static_feed!(force: false)
|
19
|
-
return if !force && GTFS::Realtime::Route.count > 0
|
20
|
-
|
21
|
-
static_data = GTFS::Source.build(@configuration.static_feed)
|
22
|
-
return unless static_data
|
23
|
-
|
24
|
-
GTFS::Realtime::Model.db.transaction do
|
25
|
-
GTFS::Realtime::CalendarDate.dataset.delete
|
26
|
-
GTFS::Realtime::CalendarDate.multi_insert(
|
27
|
-
static_data.calendar_dates.collect do |calendar_date|
|
28
|
-
{
|
29
|
-
service_id: calendar_date.service_id.strip,
|
30
|
-
date: Date.strptime(calendar_date.date, "%Y%m%d"),
|
31
|
-
exception_type: calendar_date.exception_type
|
32
|
-
}
|
33
|
-
end
|
34
|
-
)
|
35
|
-
|
36
|
-
GTFS::Realtime::Route.dataset.delete
|
37
|
-
GTFS::Realtime::Route.multi_insert(
|
38
|
-
static_data.routes.collect do |route|
|
39
|
-
{
|
40
|
-
id: route.id.strip,
|
41
|
-
short_name: route.short_name,
|
42
|
-
long_name: route.long_name,
|
43
|
-
url: route.url
|
44
|
-
}
|
45
|
-
end
|
46
|
-
)
|
47
|
-
|
48
|
-
GTFS::Realtime::Shape.dataset.delete
|
49
|
-
GTFS::Realtime::Shape.multi_insert(
|
50
|
-
static_data.shapes.collect do |shape|
|
51
|
-
{
|
52
|
-
id: shape.id.strip,
|
53
|
-
sequence: shape.pt_sequence,
|
54
|
-
latitude: shape.pt_lat.to_f,
|
55
|
-
longitude: shape.pt_lon.to_f
|
56
|
-
}
|
57
|
-
end
|
58
|
-
)
|
59
|
-
|
60
|
-
GTFS::Realtime::Stop.dataset.delete
|
61
|
-
GTFS::Realtime::Stop.multi_insert(
|
62
|
-
static_data.stops.collect do |stop|
|
63
|
-
{
|
64
|
-
id: stop.id.strip,
|
65
|
-
name: stop.name.strip,
|
66
|
-
latitude: stop.lat.to_f,
|
67
|
-
longitude: stop.lon.to_f
|
68
|
-
}
|
69
|
-
end
|
70
|
-
)
|
71
|
-
|
72
|
-
GTFS::Realtime::StopTime.dataset.delete
|
73
|
-
GTFS::Realtime::StopTime.multi_insert(
|
74
|
-
static_data.stop_times.collect do |stop_time|
|
75
|
-
{
|
76
|
-
stop_id: stop_time.stop_id.strip,
|
77
|
-
trip_id: stop_time.trip_id.strip,
|
78
|
-
arrival_time: stop_time.arrival_time,
|
79
|
-
departure_time: stop_time.departure_time,
|
80
|
-
stop_sequence: stop_time.stop_sequence.to_i
|
81
|
-
}
|
82
|
-
end
|
83
|
-
)
|
84
|
-
|
85
|
-
GTFS::Realtime::Trip.dataset.delete
|
86
|
-
GTFS::Realtime::Trip.multi_insert(
|
87
|
-
static_data.trips.collect do |trip|
|
88
|
-
{
|
89
|
-
id: trip.id.strip,
|
90
|
-
headsign: trip.headsign.strip,
|
91
|
-
route_id: trip.route_id.strip,
|
92
|
-
service_id: trip.service_id.strip,
|
93
|
-
shape_id: trip.shape_id.strip,
|
94
|
-
direction_id: trip.direction_id
|
95
|
-
}
|
96
|
-
end
|
97
|
-
)
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
def refresh_realtime_feed!
|
102
|
-
trip_updates = get_entities(@configuration.trip_updates_feed)
|
103
|
-
vehicle_positions = get_entities(@configuration.vehicle_positions_feed)
|
104
|
-
service_alerts = get_entities(@configuration.service_alerts_feed)
|
105
|
-
|
106
|
-
GTFS::Realtime::Model.db.transaction do
|
107
|
-
GTFS::Realtime::TripUpdate.dataset.delete
|
108
|
-
GTFS::Realtime::TripUpdate.multi_insert(
|
109
|
-
trip_updates.collect do |trip_update|
|
110
|
-
{
|
111
|
-
id: trip_update.id.strip,
|
112
|
-
trip_id: trip_update.trip_update.trip.trip_id.strip,
|
113
|
-
route_id: trip_update.trip_update.trip.route_id.strip
|
114
|
-
}
|
115
|
-
end
|
116
|
-
)
|
117
|
-
|
118
|
-
GTFS::Realtime::StopTimeUpdate.dataset.delete
|
119
|
-
GTFS::Realtime::StopTimeUpdate.multi_insert(
|
120
|
-
trip_updates.collect do |trip_update|
|
121
|
-
trip_update.trip_update.stop_time_update.collect do |stop_time_update|
|
122
|
-
{
|
123
|
-
trip_update_id: trip_update.id.strip,
|
124
|
-
stop_id: stop_time_update.stop_id.strip,
|
125
|
-
arrival_delay: stop_time_update.arrival ? stop_time_update.arrival.delay : nil,
|
126
|
-
arrival_time: stop_time_update.arrival ? Time.at(stop_time_update.arrival.time) : nil,
|
127
|
-
departure_delay: stop_time_update.departure ? stop_time_update.departure.delay : nil,
|
128
|
-
departure_time: stop_time_update.departure ? Time.at(stop_time_update.departure.time) : nil,
|
129
|
-
}
|
130
|
-
end
|
131
|
-
end.flatten
|
132
|
-
)
|
133
|
-
|
134
|
-
GTFS::Realtime::VehiclePosition.dataset.delete
|
135
|
-
GTFS::Realtime::VehiclePosition.multi_insert(
|
136
|
-
vehicle_positions.collect do |vehicle|
|
137
|
-
{
|
138
|
-
trip_id: vehicle.vehicle.trip.trip_id.strip,
|
139
|
-
stop_id: vehicle.vehicle.stop_id.strip,
|
140
|
-
latitude: vehicle.vehicle.position.latitude.to_f,
|
141
|
-
longitude: vehicle.vehicle.position.longitude.to_f,
|
142
|
-
bearing: vehicle.vehicle.position.bearing.to_f,
|
143
|
-
timestamp: Time.at(vehicle.vehicle.timestamp)
|
144
|
-
}
|
145
|
-
end
|
146
|
-
)
|
147
|
-
|
148
|
-
GTFS::Realtime::ServiceAlert.dataset.delete
|
149
|
-
GTFS::Realtime::ServiceAlert.multi_insert(
|
150
|
-
service_alerts.collect do |service_alert|
|
151
|
-
{
|
152
|
-
stop_id: service_alert.alert.informed_entity.first.stop_id.strip,
|
153
|
-
header_text: service_alert.alert.header_text.translation.first.text,
|
154
|
-
description_text: service_alert.alert.description_text.translation.first.text,
|
155
|
-
start_time: Time.at(service_alert.alert.active_period.first.start),
|
156
|
-
end_time: Time.at(service_alert.alert.active_period.first.end)
|
157
|
-
}
|
158
|
-
end
|
159
|
-
)
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
private
|
164
|
-
|
165
|
-
def get_entities(path)
|
166
|
-
return [] if path.nil?
|
167
|
-
|
168
|
-
if File.exists?(path)
|
169
|
-
data = File.open(path, 'r'){|f| f.read}
|
170
|
-
else
|
171
|
-
data = Net::HTTP.get(URI.parse(path))
|
172
|
-
end
|
173
|
-
feed = Transit_realtime::FeedMessage.decode(data)
|
174
|
-
feed.entity # array of entities
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
178
|
-
end
|
@@ -1,140 +0,0 @@
|
|
1
|
-
module GTFS
|
2
|
-
class Realtime
|
3
|
-
class Database
|
4
|
-
class << self
|
5
|
-
attr_writer :database_path
|
6
|
-
|
7
|
-
def path=(new_path)
|
8
|
-
@path = new_path
|
9
|
-
|
10
|
-
# This script sets up an in-memory DB so that it can be used by this gem.
|
11
|
-
# It also extends Sequel::Model so that Sequel may be used independently by
|
12
|
-
# the parent project if desired.
|
13
|
-
db = Sequel.connect(new_path || "sqlite://")
|
14
|
-
|
15
|
-
# Set up all database tables
|
16
|
-
db.create_table? :gtfs_realtime_calendar_dates do
|
17
|
-
String :service_id
|
18
|
-
Date :date
|
19
|
-
Integer :exception_type
|
20
|
-
|
21
|
-
index :service_id
|
22
|
-
end
|
23
|
-
|
24
|
-
db.create_table? :gtfs_realtime_routes do
|
25
|
-
String :id, primary_key: true
|
26
|
-
String :short_name
|
27
|
-
String :long_name
|
28
|
-
String :url
|
29
|
-
|
30
|
-
index :id
|
31
|
-
end
|
32
|
-
|
33
|
-
db.create_table? :gtfs_realtime_shapes do
|
34
|
-
String :id
|
35
|
-
Integer :sequence
|
36
|
-
Float :latitude
|
37
|
-
Float :longitude
|
38
|
-
|
39
|
-
index :id
|
40
|
-
end
|
41
|
-
|
42
|
-
db.create_table? :gtfs_realtime_stops do
|
43
|
-
String :id, primary_key: true
|
44
|
-
String :name
|
45
|
-
Float :latitude
|
46
|
-
Float :longitude
|
47
|
-
|
48
|
-
index :id
|
49
|
-
end
|
50
|
-
|
51
|
-
db.create_table? :gtfs_realtime_stop_times do
|
52
|
-
String :trip_id
|
53
|
-
String :stop_id
|
54
|
-
String :arrival_time
|
55
|
-
String :departure_time
|
56
|
-
Integer :stop_sequence
|
57
|
-
|
58
|
-
index :trip_id
|
59
|
-
index :stop_id
|
60
|
-
end
|
61
|
-
|
62
|
-
db.create_table? :gtfs_realtime_trips do
|
63
|
-
String :id, primary_key: true
|
64
|
-
String :headsign
|
65
|
-
String :route_id
|
66
|
-
String :service_id
|
67
|
-
String :shape_id
|
68
|
-
Integer :direction_id
|
69
|
-
|
70
|
-
index :id
|
71
|
-
index :route_id
|
72
|
-
end
|
73
|
-
|
74
|
-
db.create_table? :gtfs_realtime_trip_updates do
|
75
|
-
String :id, primary_key: true
|
76
|
-
String :trip_id
|
77
|
-
String :route_id
|
78
|
-
|
79
|
-
index :id
|
80
|
-
end
|
81
|
-
|
82
|
-
db.create_table? :gtfs_realtime_stop_time_updates do
|
83
|
-
String :trip_update_id
|
84
|
-
String :stop_id
|
85
|
-
Integer :arrival_delay
|
86
|
-
Time :arrival_time
|
87
|
-
Integer :departure_delay
|
88
|
-
Time :departure_time
|
89
|
-
|
90
|
-
index :trip_update_id
|
91
|
-
index :stop_id
|
92
|
-
end
|
93
|
-
|
94
|
-
db.create_table? :gtfs_realtime_vehicle_positions do
|
95
|
-
String :trip_id
|
96
|
-
String :stop_id
|
97
|
-
Float :latitude
|
98
|
-
Float :longitude
|
99
|
-
Float :bearing
|
100
|
-
Time :timestamp
|
101
|
-
|
102
|
-
index :trip_id
|
103
|
-
index :stop_id
|
104
|
-
end
|
105
|
-
|
106
|
-
db.create_table? :gtfs_realtime_service_alerts do
|
107
|
-
String :stop_id
|
108
|
-
String :header_text
|
109
|
-
Text :description_text
|
110
|
-
Time :start_time
|
111
|
-
Time :end_time
|
112
|
-
|
113
|
-
index :stop_id
|
114
|
-
end
|
115
|
-
|
116
|
-
# Set up all gtfs-realtime models to use this database
|
117
|
-
model_classes.each do |model_class|
|
118
|
-
model_class.db = db
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def model_classes
|
123
|
-
ObjectSpace.each_object(::Class).select{|klass| klass <= GTFS::Realtime::Model}
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
# If we have not defined our model parent class yet, initialize it.
|
131
|
-
if !defined?(GTFS::Realtime::Model)
|
132
|
-
GTFS::Realtime::Model = Class.new(Sequel::Model)
|
133
|
-
GTFS::Realtime::Model.plugin :many_through_many
|
134
|
-
|
135
|
-
class GTFS::Realtime::Model
|
136
|
-
def self.implicit_table_name
|
137
|
-
"gtfs_realtime_#{super}".to_sym
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|