amtrak 0.0.1 → 1.0.0

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.
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