cta_redux 0.3.3 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8ebdfcb117df8f4fe78aba18570093bca3b31889
4
- data.tar.gz: 73b88fc7bcdd14a3841514c849028f4383fda0b4
3
+ metadata.gz: 520e277cc8d9ccbb7ab6f9a619df57f2ada3c246
4
+ data.tar.gz: c6c9ec28887958b1dcd36cccdc0597365ce885f5
5
5
  SHA512:
6
- metadata.gz: a319534c7da09c458a6ed0224bfc1fb2da0e74fb44ee191d96a6cc1690563f2fbbfff94849e7893193b3a2f400b5dbf62d191b47c4e454870ba62b9321e1fc98
7
- data.tar.gz: 5588efc46e16b89723bda4b58a62a71d787dd3bf760f890ba1f5493eb99853a87241e765e084e85297a2f806d402855649f977e2a3100a213528b90f76828b0b
6
+ metadata.gz: 002852493532fcd7c94e623575bf22c0d8f5ef788932e81525bfe8115dd78efcf4c98e15e81f0fffa1a5cd9fbcb0c87e61ad92ee5d950f49588b8c8adec13cec
7
+ data.tar.gz: 448b788a0ba92cabf6722a58f8b598bbcdc47956740acf8e94e2b0c056fc701c5bcb325a386ae3970d0ba620c9e77a9c38ec80154abbbd13c5909cdcf16323b6
Binary file
@@ -13,7 +13,7 @@ module CTA
13
13
  def initialize(parsed_body, raw_body, debug)
14
14
  super(parsed_body, raw_body, debug)
15
15
  @vehicles = Array.wrap(parsed_body["bustime_response"]["vehicle"]).map do |v|
16
- bus = CTA::Bus.find_active_run(v["rt"], v["tmstmp"], (v["dly"] == "true")).first
16
+ bus = CTA::Bus.find_active_run(v["rt"], v["tmstmp"], (v["dly"] == "true"), v["rtdir"]).first
17
17
  bus.live = CTA::Bus::Live.new(v)
18
18
 
19
19
  bus
@@ -91,7 +91,7 @@ module CTA
91
91
  def initialize(parsed_body, raw_body, debug)
92
92
  super(parsed_body, raw_body, debug)
93
93
  @vehicles = Array.wrap(parsed_body["bustime_response"]["prd"]).map do |p|
94
- bus = CTA::Bus.find_active_run(p["rt"], p["tmstmp"], (p["dly"] == "true")).first
94
+ bus = CTA::Bus.find_active_run(p["rt"], p["tmstmp"], (p["dly"] == "true"), p["rtdir"]).first
95
95
  bus.live = CTA::Bus::Live.new(p, p)
96
96
 
97
97
  bus
@@ -22,9 +22,9 @@ module CTA
22
22
 
23
23
  @routes = eta_map.map do |rt, etas|
24
24
  trains = etas.map do |t|
25
- train = CTA::Train.find_active_run(t["rn"], self.timestamp, (t["isDly"] == "1")).first
25
+ train = CTA::Train.find_active_run(t["rn"], self.timestamp, (t["isDly"] == "1"), t["destNm"]).first
26
26
  if !train
27
- train = CTA::Train.find_active_run(t["rn"], self.timestamp, true).first
27
+ train = CTA::Train.find_active_run(t["rn"], self.timestamp, true, t["destNm"]).first
28
28
  end
29
29
  position = t.select { |k,v| ["lat", "lon", "heading"].include?(k) }
30
30
  train.live = CTA::Train::Live.new(position, t)
@@ -54,9 +54,9 @@ module CTA
54
54
  super(parsed_body, raw_body, debug)
55
55
 
56
56
  train_info = Array.wrap(parsed_body["ctatt"]["eta"]).first
57
- @train = CTA::Train.find_active_run(train_info["rn"], self.timestamp, (train_info["isDly"] == "1")).first
57
+ @train = CTA::Train.find_active_run(train_info["rn"], self.timestamp, (train_info["isDly"] == "1"), train_info["destNm"]).first
58
58
  if !@train
59
- @train = CTA::Train.find_active_run(train_info["rn"], self.timestamp, true).first
59
+ @train = CTA::Train.find_active_run(train_info["rn"], self.timestamp, true, train_info['destNm']).first
60
60
  end
61
61
  @train.live = CTA::Train::Live.new(parsed_body["ctatt"]["position"], parsed_body["ctatt"]["eta"])
62
62
  @predictions = @train.live.predictions
@@ -79,9 +79,9 @@ module CTA
79
79
  rt = Route.where(:route_id => route["name"].capitalize).first
80
80
 
81
81
  trains = Array.wrap(route["train"]).map do |train|
82
- t = CTA::Train.find_active_run(train["rn"], self.timestamp, (train["isDly"] == "1")).first
82
+ t = CTA::Train.find_active_run(train["rn"], self.timestamp, (train["isDly"] == "1"), train['destNm']).first
83
83
  if !t # Sometimes the CTA doesn't report things as delayed even when they ARE
84
- t = CTA::Train.find_active_run(train["rn"], self.timestamp, true).first
84
+ t = CTA::Train.find_active_run(train["rn"], self.timestamp, true, train['destNm']).first
85
85
  end
86
86
 
87
87
  if !t
@@ -30,6 +30,43 @@ module CTA
30
30
  alias_method :scheduled_trip_id, :schd_trip_id
31
31
  alias_method :run, :schd_trip_id
32
32
 
33
+ # Find a {CTA::Trip} that should be happening, given a timestamp and a route or run.
34
+ # The CTA does not return GTFS trip_id information in either the BusTracker or TrainTracker API, so
35
+ # it is actually somewhat difficult to associate an API response to a {CTA::Trip}. However, we
36
+ # know what *should* be happening at any given time. This method attempts a fuzzy find - internally,
37
+ # we often first try to find the exact Trip that should be happening according to the schedule, and
38
+ # then failing that we assume that the CTA is running late and look for trips that should have
39
+ # ended within the past 90 minutes. This almost always finds something.
40
+ # That said, however, it means we may sometimes find a {CTA::Trip} that's incorrect. In practical usage
41
+ # however, that doesn't matter too much - most Trips for a run service the same stops.
42
+ # However, to be safe, your program may wish to compare certain other bits of the API responses to ensure
43
+ # we found something valid. For example, almost all Brown line trains service the same stops, so
44
+ # finding the wrong Trip doesn't matter too much. However, a handful of Brown line runs throughout the dat
45
+ # actually change to Orange line trains at Midway - so, you may wish to verify that the destination of the
46
+ # Trip matches the reported destination of the API.
47
+ # Suggestions on how to approach this problem are most welcome (as are patches for better behavior).
48
+ # @param [String] run The run or route to search for
49
+ # @param [DateTime, String] timestamp The timestamp to search against.
50
+ # @param [true,false] fuzz Whether or not to do an exact schedule search or a fuzzy search.
51
+ def self.find_active_run(run, timestamp, fuzz = false, direction = nil)
52
+ d = timestamp.is_a?(DateTime) ? timestamp : DateTime.parse(timestamp)
53
+ wday = d.strftime("%A").downcase
54
+ end_ts = (fuzz ? (d.to_time + (60 * 60 * 6) - (90 * 60)) : d).strftime("%H:%M:%S")
55
+ Trip.with_sql(<<-SQL)
56
+ SELECT t.*
57
+ FROM trips t
58
+ JOIN stop_times st ON t.trip_id = st.trip_id
59
+ JOIN calendar c ON t.service_id = c.service_id
60
+ WHERE t.route_id = '#{run}'
61
+ #{direction ? " AND t.direction = '#{direction.gsub("bound", "")}'" : '' }
62
+ AND c.start_date <= '#{d.to_s}'
63
+ AND c.end_date >= '#{d.to_s}'
64
+ AND c.#{wday}
65
+ GROUP BY t.trip_id, st.departure_time
66
+ HAVING MAX(st.departure_time) >= '#{end_ts}'
67
+ SQL
68
+ end
69
+
33
70
  # Returns predictions for this {CTA::Bus}. Accepts all options for {CTA::BusTracker.predictions!}, and will merge in
34
71
  # it's own vehicle_id or route_id if present.
35
72
  # @param [Hash] options
@@ -4,6 +4,8 @@ module CTA
4
4
  # GTFS feed, though the CTA does not fully implement the standard.
5
5
  # @note Current columns: [:shape_id, :shape_pt_lat, :shape_pt_lon, :shape_pt_sequence, :shape_dist_traveled]
6
6
  class Shape < Sequel::Model
7
+ set_primary_key :shape_id
8
+
7
9
  # @!method shape_id
8
10
  # @return [Integer]
9
11
  # @!method shape_pt_lat
@@ -20,5 +22,9 @@ module CTA
20
22
  alias_method :sequence, :shape_pt_sequence
21
23
  alias_method :distance, :shape_dist_traveled
22
24
  alias_method :distance_traveled, :shape_dist_traveled
25
+
26
+ # @!method trips
27
+ # @return [Array<CTA::Trip>] All {CTA::Trip}s related to this {CTA::Shape}
28
+ one_to_many :trips, :key => :shape_id
23
29
  end
24
30
  end
@@ -36,6 +36,22 @@ module CTA
36
36
  }
37
37
  FRIENDLY_L_ROUTES = Hash[L_ROUTES.values.map { |r| r[:name].downcase.to_sym }.zip(L_ROUTES.keys)]
38
38
 
39
+ ANNOYING_GREEN_RUNS = CTA::DB[:stop_times].with_sql(<<-SQL).select_map(:schd_trip_id)
40
+ SELECT DISTINCT t.schd_trip_id
41
+ FROM stop_times st
42
+ JOIN trips t ON st.trip_id = t.trip_id
43
+ WHERE t.route_id = 'G'
44
+ AND st.stop_headsign = ''
45
+ SQL
46
+
47
+ HEADSIGNS = {
48
+ "54th/Cermak" => "54 / Cermak",
49
+ "Ashland/63rd" => "Ashland / 63",
50
+ "UIC-Halsted" => "UIC",
51
+ "Harlem/Lake" => "Harlem",
52
+ "95th/Dan Ryan" => "95th",
53
+ }
54
+
39
55
  # @!method route_id
40
56
  # @return [String]
41
57
  # @!method service_id
@@ -58,6 +74,62 @@ module CTA
58
74
  alias_method :scheduled_trip_id, :schd_trip_id
59
75
  alias_method :run, :schd_trip_id
60
76
 
77
+ # Find a {CTA::Trip} that should be happening, given a timestamp and a route or run.
78
+ # The CTA does not return GTFS trip_id information in either the BusTracker or TrainTracker API, so
79
+ # it is actually somewhat difficult to associate an API response to a {CTA::Trip}. However, we
80
+ # know what *should* be happening at any given time. This method attempts a fuzzy find - internally,
81
+ # we often first try to find the exact Trip that should be happening according to the schedule, and
82
+ # then failing that we assume that the CTA is running late and look for trips that should have
83
+ # ended within the past 90 minutes. This almost always finds something.
84
+ # That said, however, it means we may sometimes find a {CTA::Trip} that's incorrect. In practical usage
85
+ # however, that doesn't matter too much - most Trips for a run service the same stops.
86
+ # However, to be safe, your program may wish to compare certain other bits of the API responses to ensure
87
+ # we found something valid. For example, almost all Brown line trains service the same stops, so
88
+ # finding the wrong Trip doesn't matter too much. However, a handful of Brown line runs throughout the dat
89
+ # actually change to Orange line trains at Midway - so, you may wish to verify that the destination of the
90
+ # Trip matches the reported destination of the API.
91
+ # Suggestions on how to approach this problem are most welcome (as are patches for better behavior).
92
+ # @param [String] run The run or route to search for
93
+ # @param [DateTime, String] timestamp The timestamp to search against.
94
+ # @param [true,false] fuzz Whether or not to do an exact schedule search or a fuzzy search.
95
+ # @param [String] direction The stop headsign. Highly recommended to use because otherwise results may be inaccurate.
96
+ def self.find_active_run(run, timestamp, fuzz = false, direction = nil)
97
+ # The TrainTracker API sets the stop_headsign to 'Cottage Grove' but GTFS has it as blank...
98
+ if run == "516"
99
+ puts run
100
+ puts timestamp.to_s
101
+ puts fuzz.inspect
102
+ puts direction
103
+ end
104
+ if ANNOYING_GREEN_RUNS.any? { |r| r =~ /#{run}/ } && false
105
+ direction_str = <<-EOF
106
+ AND (st.stop_headsign = '#{(HEADSIGNS[direction] || direction).gsub("'", "''")}'
107
+ OR (t.route_id = 'G' AND st.stop_headsign = ''))
108
+ EOF
109
+ elsif direction
110
+ direction_str = "AND st.stop_headsign = '#{(HEADSIGNS[direction] || direction).gsub("'", "''")}'"
111
+ else
112
+ direction_str = ''
113
+ end
114
+ d = timestamp.is_a?(DateTime) ? timestamp : DateTime.parse(timestamp)
115
+ wday = d.strftime("%A").downcase
116
+ end_ts = (fuzz ? (d.to_time + (60 * 60 * 6) - (90 * 60)) : d).strftime("%H:%M:%S")
117
+ Trip.with_sql(<<-SQL)
118
+ SELECT t.*
119
+ FROM trips t
120
+ JOIN stop_times st ON t.trip_id = st.trip_id
121
+ JOIN calendar c ON t.service_id = c.service_id
122
+ WHERE t.schd_trip_id = 'R#{run}'
123
+ #{direction_str}
124
+ AND c.start_date <= '#{d.to_s}'
125
+ AND c.end_date >= '#{d.to_s}'
126
+ AND c.#{wday}
127
+ GROUP BY t.trip_id
128
+ HAVING MAX(st.departure_time) >= '#{end_ts}'
129
+ ORDER BY st.departure_time ASC
130
+ SQL
131
+ end
132
+
61
133
  # Follows a train, using the TrainTracker follow API
62
134
  # @return [CTA::TrainTracker::FollowResponse] A {CTA::TrainTracker::FollowResponse} with predictions for this train
63
135
  def follow!
@@ -42,6 +42,10 @@ module CTA
42
42
  # @return [Array<CTA::Stop>] All {CTA::Stop}s serviced on this {CTA::Trip}
43
43
  many_to_many :stops, :left_key => :trip_id, :right_key => :stop_id, :join_table => :stop_times
44
44
 
45
+ # @!method shapes
46
+ # @return [Array<CTA::Shape>] All {CTA::Shape}s related to this {CTA::Trip}
47
+ many_to_many :shapes, :left_key => :trip_id, :right_key => :shape_id, :join_table => :trips
48
+
45
49
  # @!method route_id
46
50
  # @return [String]
47
51
  # @!method service_id
@@ -63,47 +67,5 @@ module CTA
63
67
  alias_method :id, :route_id
64
68
  alias_method :scheduled_trip_id, :schd_trip_id
65
69
  alias_method :run, :schd_trip_id
66
-
67
- # Find a {CTA::Trip} that should be happening, given a timestamp and a route or run.
68
- # The CTA does not return GTFS trip_id information in either the BusTracker or TrainTracker API, so
69
- # it is actually somewhat difficult to associate an API response to a {CTA::Trip}. However, we
70
- # know what *should* be happening at any given time. This method attempts a fuzzy find - internally,
71
- # we often first try to find the exact Trip that should be happening according to the schedule, and
72
- # then failing that we assume that the CTA is running late and look for trips that should have
73
- # ended within the past 90 minutes. This almost always finds something.
74
- # That said, however, it means we may sometimes find a {CTA::Trip} that's incorrect. In practical usage
75
- # however, that doesn't matter too much - most Trips for a run service the same stops.
76
- # However, to be safe, your program may wish to compare certain other bits of the API responses to ensure
77
- # we found something valid. For example, almost all Brown line trains service the same stops, so
78
- # finding the wrong Trip doesn't matter too much. However, a handful of Brown line runs throughout the dat
79
- # actually change to Orange line trains at Midway - so, you may wish to verify that the destination of the
80
- # Trip matches the reported destination of the API.
81
- # Suggestions on how to approach this problem are most welcome (as are patches for better behavior).
82
- # @param [String] run The run or route to search for
83
- # @param [DateTime, String] timestamp The timestamp to search against.
84
- # @param [true,false] fuzz Whether or not to do an exact schedule search or a fuzzy search.
85
- def self.find_active_run(run, timestamp, fuzz = false)
86
- if self.to_s == "CTA::Train" # This is admittedly hacky.
87
- join_str = "WHERE t.schd_trip_id = 'R#{run}'"
88
- else
89
- join_str = "WHERE t.route_id = '#{run}'"
90
- end
91
- d = timestamp.is_a?(DateTime) ? timestamp : DateTime.parse(timestamp)
92
- wday = d.strftime("%A").downcase
93
- end_ts = (fuzz ? (d.to_time + (60 * 60 * 6) - (90 * 60)) : d).strftime("%H:%M:%S")
94
- Trip.with_sql(<<-SQL)
95
- SELECT t.*
96
- FROM trips t
97
- JOIN stop_times st ON t.trip_id = st.trip_id
98
- JOIN calendar c ON t.service_id = c.service_id
99
- #{join_str}
100
- AND c.start_date <= '#{d.to_s}'
101
- AND c.end_date >= '#{d.to_s}'
102
- AND c.#{wday}
103
- GROUP BY t.trip_id, st.departure_time
104
- HAVING MAX(st.departure_time) >= '#{end_ts}'
105
- SQL
106
- end
107
-
108
70
  end
109
71
  end
@@ -1,3 +1,3 @@
1
1
  module CTA
2
- VERSION = "0.3.3"
2
+ VERSION = "0.3.4"
3
3
  end
@@ -60,11 +60,18 @@ RSpec.describe CTA::TrainTracker do
60
60
  expect(response.routes.size).to eq(8)
61
61
  expect(response.trains.size).to eq(80)
62
62
 
63
- expect(response.trains.last.route.route_id).to eq("Y")
63
+ expect(response.trains.last.route.route_id).to eq("P")
64
64
  expect(response.trains.first.live.lon).to eq(-87.65338)
65
65
  expect(response.predictions.first.route.route_id).to eq("Red")
66
66
  expect(response.predictions.first.destination.stop_id).to eq(30173)
67
67
  expect(response.predictions.first.trip.service_id).to eq(104701)
68
68
  end
69
69
  end
70
+
71
+ describe "bugs" do
72
+ it "uses proper station IDs for Green line runs, which are wrong from the CTA GTFS feed" do
73
+ trip = CTA::Trip[47085599996]
74
+ expect(trip.stops.map(&:stop_id)).to include(30033)
75
+ end
76
+ end
70
77
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cta_redux
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Hayworth
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-16 00:00:00.000000000 Z
11
+ date: 2015-02-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler