amtrak 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (23) hide show
  1. checksums.yaml +4 -4
  2. data/lib/amtrak/train_fetcher/main_page.rb +2 -4
  3. data/lib/amtrak/train_parser.rb +31 -31
  4. data/lib/amtrak/version.rb +1 -1
  5. data/spec/amtrak/train_fetcher/main_page_spec.rb +4 -4
  6. data/spec/amtrak/train_fetcher/train_page_spec.rb +5 -5
  7. data/spec/amtrak/train_fetcher_spec.rb +16 -16
  8. data/spec/amtrak/train_parser_spec.rb +20 -177
  9. data/spec/amtrak_spec.rb +5 -228
  10. data/spec/fixtures/html/pvd_to_bby.html +2803 -2392
  11. data/spec/fixtures/json/_get.json +1 -0
  12. data/spec/fixtures/json/_parse.json +1 -0
  13. data/spec/fixtures/vcr/Amtrak/_get/returns_a_list_of_train_times.yml +599 -690
  14. data/spec/fixtures/vcr/Amtrak_TrainFetcher/_get/does_the_same_as_get.yml +455 -718
  15. data/spec/fixtures/vcr/Amtrak_TrainFetcher/_get/given_a_valid_date_and_invalid_train_stations/does_not_include_various_classes_and_includes_an_error.yml +129 -115
  16. data/spec/fixtures/vcr/Amtrak_TrainFetcher/_get/given_a_valid_date_and_train_stations/includes_various_classes.yml +449 -717
  17. data/spec/fixtures/vcr/Amtrak_TrainFetcher/_get/given_an_invalid_date_and_valid_train_stations/does_not_include_various_classes_and_includes_an_error.yml +127 -109
  18. data/spec/fixtures/vcr/Amtrak_TrainFetcher_MainPage/_session_id/pulls_the_session_id_from_the_cookies.yml +295 -366
  19. data/spec/fixtures/vcr/Amtrak_TrainFetcher_MainPage/_total_pages/when_more_than_one_page_exists_on_the_website/returns_2.yml +295 -358
  20. data/spec/fixtures/vcr/Amtrak_TrainFetcher_MainPage/_total_pages/when_only_one_page_exists_on_the_website/returns_1.yml +289 -363
  21. data/spec/fixtures/vcr/Amtrak_TrainFetcher_TrainPage/_get/when_it_works/includes_various_classes.yml +164 -213
  22. metadata +6 -4
  23. data/spec/fixtures/vcr/Amtrak_TrainFetcher_MainPage/_total_pages/when_more_than_one_page_exists_on_the_website/returns_1.yml +0 -1076
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 893ffef1c08c1763b3a34c0f70d9dd303f89385f
4
- data.tar.gz: c2e940a65b8bf344359b2ca25a15b0c853776c3a
3
+ metadata.gz: 2ec72cfc1f5a1b52b737a3b1744af0f11a097347
4
+ data.tar.gz: 4552142bd84a4699d7fad70183378a6d5ce1523a
5
5
  SHA512:
6
- metadata.gz: f98144098bbe5944ababe3817acc7713a838279dc63b1a9cacf5af17a34584faaf879c8ebce826a462867ddab44bce7fb5db5e1fca9ad4acce5ad05a60edf442
7
- data.tar.gz: 42ce40b14aeb3341e0d46e20512b2275fb80e02d51cdf03ff475314974084db1190244c340f79cf6c175add675cc2d261e0d3a28bf1cd6249008c109cc10dd84
6
+ metadata.gz: 1766915385f034a27c00210e732f9ff4b7725323d312153d732074b0d6c3da19806c3de6e1ff61b89431ff0d15bdd187c38c2e52f765d787ff19888ed1467560
7
+ data.tar.gz: 9c56312cbf9c98572d199fcd437dcff6e0abd25fe2252ea0b5f124f9bab01dbaa3c70eb49235a53deb1895129ebdfa9c89ab48a87261d3988d680e8e20d5e437
@@ -33,11 +33,9 @@ module Amtrak
33
33
  {
34
34
  "_handler=amtrak.presentation.handler.request.rail.AmtrakRailTrainStatusSearchRequestHandler/_xpath=/sessionWorkflow/productWorkflow[@product='Rail']" => '',
35
35
  "/sessionWorkflow/productWorkflow[@product='Rail']/tripRequirements/journeyRequirements[1]/departDate.date" => departure_date,
36
+ "/sessionWorkflow/productWorkflow[@product='Rail']/tripRequirements/@trainStatusType" => 'statusByCityPair',
37
+ "/sessionWorkflow/productWorkflow[@product='Rail']/tripRequirements/journeyRequirements[1]/departDate/@radioSelect" => 'arrivalTime',
36
38
  'requestor' => 'amtrak.presentation.handler.page.rail.AmtrakRailGetTrainStatusPageHandler',
37
- 'xwdf_trainNumber' => "/sessionWorkflow/productWorkflow[@product='Rail']/tripRequirements/journeyRequirements[1]/segmentRequirements[1]/serviceCode",
38
- 'wdf_trainNumber' => 'optional',
39
- 'xwdf_SortBy' => "/sessionWorkflow/productWorkflow[@product='Rail']/tripRequirements/journeyRequirements[1]/departDate/@radioSelect",
40
- 'wdf_SortBy' => 'arrivalTime',
41
39
  'xwdf_origin' => "/sessionWorkflow/productWorkflow[@product='Rail']/travelSelection/journeySelection[1]/departLocation/search",
42
40
  'wdf_origin' => from.to_s,
43
41
  'xwdf_destination' => "/sessionWorkflow/productWorkflow[@product='Rail']/travelSelection/journeySelection[1]/arriveLocation/search",
@@ -19,12 +19,11 @@ module Amtrak
19
19
  def parse
20
20
  trains = []
21
21
 
22
- until train_nodes.empty?
23
- departure, arrival = train_nodes.shift(2)
22
+ while train_node = train_nodes.shift
24
23
  trains << {
25
- number: parse_train_number(departure),
26
- departure: parse_train(departure),
27
- arrival: parse_train(arrival)
24
+ number: parse_train_number(train_node),
25
+ departure: parse_train(find_depart_status(train_node)),
26
+ arrival: parse_train(find_arrive_status(train_node))
28
27
  }
29
28
  end
30
29
 
@@ -35,33 +34,39 @@ module Amtrak
35
34
 
36
35
  def train_nodes
37
36
  @train_nodes ||= document.search(
38
- "//tr[contains(@class, 'status_result')]"
37
+ "//div[@id='train_status_resp_by_citypair']"
39
38
  ).tap { |results| fail 'No trains found' unless results.count > 0 }.to_a
40
39
  end
41
40
 
41
+ def find_depart_status(node)
42
+ find!(node, ".//div[@id='resp_by_citypair_depart_status_details']")
43
+ end
44
+
45
+ def find_arrive_status(node)
46
+ find!(node, ".//div[@id='resp_by_citypair_arrive_status_details']")
47
+ end
48
+
42
49
  def parse_train_number(node)
43
50
  find!(
44
- node, ".//th[@class='service']/div[@class='route_num']/text()"
51
+ node,
52
+ ".//div[@id='resp_by_citypair_subheading']/\
53
+ div[@id='resp_by_citypair_subheading_trainname']/text()"
45
54
  ).to_s.to_i
46
55
  end
47
56
 
48
57
  def parse_train(node) # rubocop:disable Metrics/MethodLength
49
- scheduled_date = find!(
50
- node, ".//td[@class='scheduled']/div[@class='date']/text()"
51
- ).to_s
52
- estimated_date = find!(
53
- node, ".//td[@class='act_est']/div[@class='date']/text()"
58
+ date = find!(
59
+ node, ".//div[@class='arriveDepartDate']/text()"
54
60
  ).to_s
55
- scheduled_time = remove_parentheses(
56
- find!(node, ".//td[@class='scheduled']/div[@class='time']/text()").to_s
57
- )
58
- estimated_time = remove_parentheses(
59
- find!(node, ".//td[@class='act_est']/div[@class='time']/text()").to_s
61
+ scheduled_time = clean_msg(
62
+ find!(node, ".//div[@class='scheduledArriveDepartMsg']/text()").to_s
60
63
  )
64
+ estimated_time = find(
65
+ node, ".//div[@class='arriveDepartTime']/text()"
66
+ ).to_s
61
67
 
62
68
  {
63
- scheduled_date: scheduled_date,
64
- estimated_date: estimated_date,
69
+ date: date,
65
70
  scheduled_time: scheduled_time,
66
71
  estimated_time: estimated_time
67
72
  }
@@ -71,20 +76,15 @@ module Amtrak
71
76
  node.search(xpath).tap { |rs| fail "#{rs.count} results" if rs.count > 1 }
72
77
  end
73
78
 
74
- def make_datetime(date, time)
75
- if date.nil? || time.nil?
76
- return
77
- else
78
- DateTime.parse("#{date} at #{time}")
79
- end
79
+ def find(node, xpath)
80
+ find!(node, xpath)
81
+ rescue RuntimeError # rubocop:disable Lint/HandleExceptions
80
82
  end
81
83
 
82
- def remove_parentheses(time_string)
83
- if matches = /\(([^)]+)\)/.match(time_string)
84
- matches[1]
85
- else
86
- time_string
87
- end
84
+ def clean_msg(time_msg)
85
+ return unless matches = /\d+:\d+ (a|p)m/.match(time_msg)
86
+
87
+ matches[0]
88
88
  end
89
89
  end
90
90
  end
@@ -1,6 +1,6 @@
1
1
  module Amtrak
2
2
  # This module holds the Amtrak version
3
3
  module Version
4
- VERSION = '0.0.1'
4
+ VERSION = '1.0.0'
5
5
  end
6
6
  end
@@ -34,7 +34,7 @@ describe Amtrak::TrainFetcher::MainPage do
34
34
 
35
35
  describe '#total_pages' do
36
36
  context 'when only one page exists on the website' do
37
- subject { described_class.new('pvd', 'bby', date: Date.parse('2014-11-28')) }
37
+ subject { described_class.new('pvd', 'bby', date: Date.parse('2014-12-07')) }
38
38
 
39
39
  it 'returns 1', :vcr do
40
40
  expect(subject.total_pages).to eq(1)
@@ -42,7 +42,7 @@ describe Amtrak::TrainFetcher::MainPage do
42
42
  end
43
43
 
44
44
  context 'when more than one page exists on the website' do
45
- subject { described_class.new('pvd', 'bby', date: Date.parse('2014-11-27')) }
45
+ subject { described_class.new('pvd', 'bby', date: Date.parse('2014-12-06')) }
46
46
 
47
47
  it 'returns 2', :vcr do
48
48
  expect(subject.total_pages).to eq(2)
@@ -51,9 +51,9 @@ describe Amtrak::TrainFetcher::MainPage do
51
51
  end
52
52
 
53
53
  describe '#session_id' do
54
- subject { described_class.new('pvd', 'bby', date: Date.parse('2014-11-28')) }
54
+ subject { described_class.new('pvd', 'bby', date: Date.parse('2014-12-06')) }
55
55
  it 'pulls the session id from the cookies', :vcr do
56
- expect(subject.session_id).to eq('0000kOxPFtO4mDoSiIGk2yzvAz6:187j4dq9a')
56
+ expect(subject.session_id).to eq('0000faPsyYZwp2n8Wb_4BDhukyg:187j59p07')
57
57
  end
58
58
  end
59
59
 
@@ -5,18 +5,18 @@ describe Amtrak::TrainFetcher::TrainPage do
5
5
 
6
6
  describe '#get', :vcr do
7
7
  context 'when it works' do
8
- let(:session_id) { '0000ITjAiGUWm-mBBpAyeGZ43Rv:187j4ddrq' }
8
+ let(:session_id) { '0000faPsyYZwp2n8Wb_4BDhukyg:187j59p07' }
9
9
  let(:page) { '1' }
10
10
 
11
11
  it 'includes various classes' do
12
- expect(subject).to include('route_num')
13
- expect(subject).to include('scheduled')
14
- expect(subject).to include('act_est')
12
+ expect(subject).to include('resp_by_citypair_subheading_trainname')
13
+ expect(subject).to include('resp_by_citypair_depart_status_details')
14
+ expect(subject).to include('resp_by_citypair_arrive_status_details')
15
15
  end
16
16
  end
17
17
 
18
18
  context 'when Excon raises an error' do
19
- let(:session_id) { '0000ITjAiGUWm-mBBpAyeGZ43Rv:187j4ddrq' }
19
+ let(:session_id) { '0000faPsyYZwp2n8Wb_4BDhukyg:187j59p07' }
20
20
  let(:page) { '1' }
21
21
 
22
22
  it 'reraises as a TrainFetcher::Error' do
@@ -3,56 +3,56 @@ require 'spec_helper'
3
3
  describe Amtrak::TrainFetcher do
4
4
  describe '.get', :vcr do
5
5
  let(:output) do
6
- described_class.get('pvd', 'bby', date: Date.parse('2014-11-27'))
6
+ described_class.get('pvd', 'bby', date: Date.parse('2014-12-07'))
7
7
  end
8
8
 
9
9
  it 'does the same as #get' do
10
- expect(output.join).to include('route_num')
11
- expect(output.join).to include('scheduled')
12
- expect(output.join).to include('act_est')
10
+ expect(output.join).to include('resp_by_citypair_subheading_trainname')
11
+ expect(output.join).to include('resp_by_citypair_depart_status_details')
12
+ expect(output.join).to include('resp_by_citypair_arrive_status_details')
13
13
  end
14
14
  end
15
15
 
16
16
  describe '#get', :vcr do
17
17
  describe 'given a valid date and train stations' do
18
18
  subject do
19
- described_class.new('pvd', 'bby', date: Date.parse('2014-11-27'))
19
+ described_class.new('pvd', 'bby', date: Date.parse('2014-12-07'))
20
20
  end
21
21
 
22
22
  let(:output) { subject.get }
23
23
 
24
24
  it 'includes various classes' do
25
- expect(output.join).to include('route_num')
26
- expect(output.join).to include('scheduled')
27
- expect(output.join).to include('act_est')
25
+ expect(output.join).to include('resp_by_citypair_subheading_trainname')
26
+ expect(output.join).to include('resp_by_citypair_depart_status_details')
27
+ expect(output.join).to include('resp_by_citypair_arrive_status_details')
28
28
  end
29
29
  end
30
30
 
31
31
  describe 'given an invalid date and valid train stations' do
32
32
  subject do
33
- described_class.new('pvd', 'bby', date: Date.parse('2014-11-6'))
33
+ described_class.new('pvd', 'bby', date: Date.parse('2014-11-06'))
34
34
  end
35
35
 
36
36
  let(:output) { subject.get }
37
37
 
38
38
  it 'does not include various classes and includes an error' do
39
- expect(output.join).to_not include('route_num')
40
- expect(output.join).to_not include('scheduled')
41
- expect(output.join).to_not include('act_est')
39
+ expect(output.join).to_not include('resp_by_citypair_subheading_trainname')
40
+ expect(output.join).to_not include('resp_by_citypair_depart_status_details')
41
+ expect(output.join).to_not include('resp_by_citypair_arrive_status_details')
42
42
  end
43
43
  end
44
44
 
45
45
  describe 'given a valid date and invalid train stations' do
46
46
  subject do
47
- described_class.new('askdf', 'bby', date: Date.parse('2014-11-27'))
47
+ described_class.new('askdf', 'bby', date: Date.parse('2014-12-07'))
48
48
  end
49
49
 
50
50
  let(:output) { subject.get }
51
51
 
52
52
  it 'does not include various classes and includes an error' do
53
- expect(output.join).to_not include('route_num')
54
- expect(output.join).to_not include('scheduled')
55
- expect(output.join).to_not include('act_est')
53
+ expect(output.join).to_not include('resp_by_citypair_subheading_trainname')
54
+ expect(output.join).to_not include('resp_by_citypair_depart_status_details')
55
+ expect(output.join).to_not include('resp_by_citypair_arrive_status_details')
56
56
  end
57
57
  end
58
58
  end
@@ -1,75 +1,33 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Amtrak::TrainParser do
4
- describe '#remove_parentheses' do
4
+ describe '#clean_msg' do
5
5
  subject { described_class.new('') }
6
- let(:output) { subject.remove_parentheses(message) }
6
+ let(:output) { subject.clean_msg(message) }
7
7
 
8
- context 'on a string with no surrounding parentheses' do
9
- let(:message) { '3:30 pm' }
10
- let(:expected) { '3:30 pm' }
11
-
12
- it 'returns the statement' do
13
- expect(output).to eq(expected)
14
- end
15
- end
16
-
17
- context 'on a string with a leading parentheses' do
18
- let(:message) { '(3:30 pm' }
19
- let(:expected) { '(3:30 pm' }
20
-
21
- it 'returns the statement' do
22
- expect(output).to eq(expected)
23
- end
24
- end
25
-
26
- context 'on a string with a trailing parentheses' do
27
- let(:message) { '3:30 pm)' }
28
- let(:expected) { '3:30 pm)' }
8
+ context 'on a string with no time' do
9
+ let(:message) { 'Scheduled arrival' }
10
+ let(:expected) { nil }
29
11
 
30
- it 'returns the statement' do
12
+ it 'returns nil' do
31
13
  expect(output).to eq(expected)
32
14
  end
33
15
  end
34
16
 
35
- context 'on a string with surrounding parentheses' do
36
- let(:message) { '(3:30 pm)' }
17
+ context 'on a string with a time' do
18
+ let(:message) { 'Scheduled arrival 3:30 pm' }
37
19
  let(:expected) { '3:30 pm' }
38
20
 
39
- it 'returns the statement without parentheses' do
21
+ it 'returns the time' do
40
22
  expect(output).to eq(expected)
41
23
  end
42
24
  end
43
- end
44
-
45
- describe '#make_datetime' do
46
- subject { described_class.new('') }
47
- let(:output) { subject.make_datetime(date, time) }
48
25
 
49
- context 'given no date' do
50
- let(:date) { nil }
51
- let(:time) { '3:30 pm' }
52
-
53
- it 'returns nil' do
54
- expect(output).to be_nil
55
- end
56
- end
57
-
58
- context 'given no time' do
59
- let(:date) { 'Wed Nov 19, 2014' }
60
- let(:time) { nil }
61
-
62
- it 'returns nil' do
63
- expect(output).to be_nil
64
- end
65
- end
66
-
67
- context 'given a string date and time' do
68
- let(:date) { 'Wed Nov 19, 2014' }
69
- let(:time) { '3:30 pm' }
70
- let(:expected) { DateTime.new(2014, 11, 19, 15, 30) }
26
+ context 'on a string with only a time' do
27
+ let(:message) { '3:30 pm' }
28
+ let(:expected) { '3:30 pm' }
71
29
 
72
- it 'returns a datetime' do
30
+ it 'returns the time' do
73
31
  expect(output).to eq(expected)
74
32
  end
75
33
  end
@@ -90,131 +48,16 @@ describe Amtrak::TrainParser do
90
48
  let(:document) do
91
49
  File.read(File.join('spec', 'fixtures', 'html', 'pvd_to_bby.html'))
92
50
  end
51
+ let(:expected) do
52
+ JSON.parse(
53
+ File.read(File.join('spec', 'fixtures', 'json', '_parse.json')),
54
+ symbolize_names: true
55
+ )
56
+ end
93
57
 
94
58
  context 'without an error' do
95
59
  it 'returns a list of train times' do
96
- expect(output).to eq([
97
- {
98
- number: 174,
99
- departure: {
100
- scheduled_date: 'Wed Nov 19, 2014',
101
- estimated_date: '',
102
- scheduled_time: '5:30 pm',
103
- estimated_time: '5:52 pm'
104
- },
105
- arrival: {
106
- scheduled_date: 'Wed Nov 19, 2014',
107
- estimated_date: 'Wed Nov 19, 2014',
108
- scheduled_time: '6:25 pm',
109
- estimated_time: '6:27 pm'
110
- }
111
- },
112
- {
113
- number: 2164,
114
- departure: {
115
- scheduled_date: 'Wed Nov 19, 2014',
116
- estimated_date: '',
117
- scheduled_time: '5:50 pm',
118
- estimated_time: '6:45 pm'
119
- },
120
- arrival: {
121
- scheduled_date: 'Wed Nov 19, 2014',
122
- estimated_date: 'Wed Nov 19, 2014',
123
- scheduled_time: '6:34 pm',
124
- estimated_time: '7:14 pm'
125
- }
126
- },
127
- {
128
- number: 2166,
129
- departure: {
130
- scheduled_date: 'Wed Nov 19, 2014',
131
- estimated_date: '',
132
- scheduled_time: '6:54 pm',
133
- estimated_time: ''
134
- },
135
- arrival: {
136
- scheduled_date: 'Wed Nov 19, 2014',
137
- estimated_date: 'Wed Nov 19, 2014',
138
- scheduled_time: '7:35 pm',
139
- estimated_time: '7:28 pm'
140
- }
141
- },
142
- {
143
- number: 176,
144
- departure: {
145
- scheduled_date: 'Wed Nov 19, 2014',
146
- estimated_date: 'Wed Nov 19, 2014',
147
- scheduled_time: '7:19 pm',
148
- estimated_time: '7:22 pm'
149
- },
150
- arrival: {
151
- scheduled_date: 'Wed Nov 19, 2014',
152
- estimated_date: 'Wed Nov 19, 2014',
153
- scheduled_time: '8:06 pm',
154
- estimated_time: '7:51 pm'
155
- }
156
- },
157
- {
158
- number: 2168,
159
- departure: {
160
- scheduled_date: 'Wed Nov 19, 2014',
161
- estimated_date: 'Wed Nov 19, 2014',
162
- scheduled_time: '7:56 pm',
163
- estimated_time: '7:57 pm'
164
- },
165
- arrival: {
166
- scheduled_date: 'Wed Nov 19, 2014',
167
- estimated_date: 'Wed Nov 19, 2014',
168
- scheduled_time: '8:38 pm',
169
- estimated_time: '8:34 pm'
170
- }
171
- },
172
- {
173
- number: 2170,
174
- departure: {
175
- scheduled_date: 'Wed Nov 19, 2014',
176
- estimated_date: 'Wed Nov 19, 2014',
177
- scheduled_time: '8:54 pm',
178
- estimated_time: '8:55 pm'
179
- },
180
- arrival: {
181
- scheduled_date: 'Wed Nov 19, 2014',
182
- estimated_date: 'Wed Nov 19, 2014',
183
- scheduled_time: '9:34 pm',
184
- estimated_time: '9:32 pm'
185
- }
186
- },
187
- {
188
- number: 94,
189
- departure: {
190
- scheduled_date: 'Wed Nov 19, 2014',
191
- estimated_date: 'Wed Nov 19, 2014',
192
- scheduled_time: '9:16 pm',
193
- estimated_time: '9:22 pm'
194
- },
195
- arrival: {
196
- scheduled_date: 'Wed Nov 19, 2014',
197
- estimated_date: 'Wed Nov 19, 2014',
198
- scheduled_time: '10:02 pm',
199
- estimated_time: '9:51 pm'
200
- }
201
- },
202
- {
203
- number: 2172,
204
- departure: {
205
- scheduled_date: 'Wed Nov 19, 2014',
206
- estimated_date: 'Wed Nov 19, 2014',
207
- scheduled_time: '9:54 pm',
208
- estimated_time: '9:55 pm'
209
- },
210
- arrival: {
211
- scheduled_date: 'Wed Nov 19, 2014',
212
- estimated_date: 'Wed Nov 19, 2014',
213
- scheduled_time: '10:35 pm',
214
- estimated_time: '10:32 pm'
215
- }
216
- }
217
- ])
60
+ expect(output).to eq(expected)
218
61
  end
219
62
 
220
63
  context 'with an error' do