cta_redux 0.3.3 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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