amtrak 2.0.0 → 3.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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +5 -0
  3. data/README.markdown +184 -2
  4. data/amtrak.gemspec +3 -4
  5. data/lib/amtrak.rb +2 -3
  6. data/lib/amtrak/train_fetcher.rb +25 -28
  7. data/lib/amtrak/train_parser.rb +30 -86
  8. data/lib/amtrak/version.rb +1 -1
  9. data/spec/amtrak/train_fetcher_spec.rb +26 -22
  10. data/spec/amtrak/train_parser_spec.rb +8 -64
  11. data/spec/amtrak_spec.rb +1 -2
  12. data/spec/fixtures/json/_get.json +223 -28
  13. data/spec/fixtures/json/_parse.json +211 -42
  14. data/spec/fixtures/json/pvd_to_bby.json +1131 -0
  15. data/spec/fixtures/vcr/Amtrak/_get/returns_a_list_of_train_times.yml +1160 -1250
  16. data/spec/fixtures/vcr/Amtrak_TrainFetcher/_get/does_the_same_as_get.yml +1159 -1628
  17. data/spec/fixtures/vcr/Amtrak_TrainFetcher/_get/given_a_valid_date_and_invalid_train_stations/does_not_include_various_keys_and_includes_an_error.yml +66 -0
  18. data/spec/fixtures/vcr/Amtrak_TrainFetcher/_get/given_a_valid_date_and_train_stations/includes_various_keys.yml +1181 -0
  19. data/spec/fixtures/vcr/Amtrak_TrainFetcher/_get/given_an_invalid_date_and_valid_train_stations/does_not_include_various_keys_and_includes_an_error.yml +66 -0
  20. metadata +22 -54
  21. data/lib/amtrak/train_fetcher/main_page.rb +0 -83
  22. data/lib/amtrak/train_fetcher/train_page.rb +0 -52
  23. data/spec/amtrak/train_fetcher/main_page_spec.rb +0 -53
  24. data/spec/amtrak/train_fetcher/train_page_spec.rb +0 -18
  25. data/spec/fixtures/html/pvd_to_bby.html +0 -2596
  26. data/spec/fixtures/html/pvd_to_bby_cancelled.html +0 -2671
  27. data/spec/fixtures/json/_parse_cancelled.json +0 -132
  28. 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 +0 -1073
  29. data/spec/fixtures/vcr/Amtrak_TrainFetcher/_get/given_a_valid_date_and_train_stations/includes_various_classes.yml +0 -1650
  30. 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 +0 -1071
  31. data/spec/fixtures/vcr/Amtrak_TrainFetcher_MainPage/_session_id/pulls_the_session_id_from_the_cookies.yml +0 -1071
  32. data/spec/fixtures/vcr/Amtrak_TrainFetcher_MainPage/_total_pages/when_more_than_one_page_exists_on_the_website/returns_2.yml +0 -1263
  33. data/spec/fixtures/vcr/Amtrak_TrainFetcher_MainPage/_total_pages/when_only_one_page_exists_on_the_website/returns_1.yml +0 -1154
  34. data/spec/fixtures/vcr/Amtrak_TrainFetcher_TrainPage/_get/when_it_works/includes_various_classes.yml +0 -198
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f6b65ee543c0ab3f6c50c3f6af2d873fdb6ea8bf
4
- data.tar.gz: 0bbe04375b423a44476f15dceaa7f85a293756fd
3
+ metadata.gz: 6be6d049d542cd9aba8849a9226b44db46bd9df4
4
+ data.tar.gz: fb1351d68d0cd8ca904a16f649af25914c30b758
5
5
  SHA512:
6
- metadata.gz: 458227e5403222869fe87f704ee5ea19aeb61c936299fd5a4684979531ec473240fb5bec3df3bbd6bf7de963b2d0b7483d360cb0bdefed152ef333c49fe01a0e
7
- data.tar.gz: 7e3ca8eea40bda322a3f5a7edefbf090e5a50cd6933726eb81a2919da430fc39b860fb276d3e7b8036f984c9715120f54482649c83e4edad33ab743e530840da
6
+ metadata.gz: 0396b5b99590d47f2503e089d756c5481d6d5d70502a33a76dc16d790bbcfe498d9cb3d9f92a9d88a11b7500f77b73099ad5b516bbf8df8b4566181aacf1a3db
7
+ data.tar.gz: 39a1aea72b92c97ef37fe6c28e6cba74d304453380d37bb77e9ea961c3933e6101ffd7d01a023760764d1d4993019e4a1f6686e552e0f77b5bb9d579a1e622fb
data/.rubocop.yml CHANGED
@@ -4,3 +4,8 @@ Metrics/MethodLength:
4
4
  Max: 12
5
5
  Metrics/LineLength:
6
6
  Max: 100
7
+ Style/BlockLength:
8
+ Exclude:
9
+ - 'Rakefile'
10
+ - '**/*.rake'
11
+ - 'spec/**/*.rb'
data/README.markdown CHANGED
@@ -1,3 +1,185 @@
1
- # Amtrak
1
+ ## Amtrak
2
+ ### Pulls Amtrak train scheduled and estimated departure times
3
+
4
+ #### Installation
5
+
6
+ Install `bundler` if you haven't already:
7
+
8
+ ```
9
+ $ gem install bundler
10
+ ```
11
+
12
+ Specify your dependencies in a Gemfile in your project's root:
13
+
14
+ ```
15
+ source 'https://rubygems.org'
16
+ gem 'amtrak'
17
+ ```
18
+
19
+ In a terminal window, run:
20
+
21
+ ```
22
+ $ bundle install
23
+ $ git add Gemfile Gemfile.lock
24
+ ```
25
+
26
+ #### Usage
27
+
28
+ Require the Gem:
29
+
30
+ ```
31
+ require 'amtrak'
32
+ ```
33
+
34
+ Make a request:
35
+
36
+ ```
37
+ Amtrak.get('NYP', 'PHL')
38
+ ```
39
+
40
+ Example response:
41
+
42
+ ```
43
+ [{:number=>89,
44
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"06:02:00", :estimated_time=>nil},
45
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"06:02:00", :estimated_time=>nil}},
46
+ {:number=>2107,
47
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"07:00:00", :estimated_time=>nil},
48
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"07:00:00", :estimated_time=>nil}},
49
+ {:number=>183,
50
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"07:05:00", :estimated_time=>nil},
51
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"07:05:00", :estimated_time=>nil}},
52
+ {:number=>641,
53
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"07:17:00", :estimated_time=>nil},
54
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"07:17:00", :estimated_time=>nil}},
55
+ {:number=>79,
56
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"07:25:00", :estimated_time=>nil},
57
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"07:25:00", :estimated_time=>nil}},
58
+ {:number=>2109,
59
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"08:00:00", :estimated_time=>nil},
60
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"08:00:00", :estimated_time=>nil}},
61
+ {:number=>185,
62
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"08:10:00", :estimated_time=>nil},
63
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"08:10:00", :estimated_time=>nil}},
64
+ {:number=>2151,
65
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"09:00:00", :estimated_time=>"09:00:00"},
66
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"09:00:00", :estimated_time=>"09:00:00"}},
67
+ {:number=>643,
68
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"09:30:00", :estimated_time=>"09:30:00"},
69
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"09:30:00", :estimated_time=>"09:30:00"}},
70
+ {:number=>141,
71
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"09:35:00", :estimated_time=>"09:35:00"},
72
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"09:35:00", :estimated_time=>"09:35:00"}},
73
+ {:number=>2153,
74
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"10:00:00", :estimated_time=>"10:00:00"},
75
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"10:00:00", :estimated_time=>"10:00:00"}},
76
+ {:number=>95,
77
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"10:35:00", :estimated_time=>"10:35:00"},
78
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"10:35:00", :estimated_time=>"10:35:00"}},
79
+ {:number=>2155,
80
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"11:00:00", :estimated_time=>"11:00:00"},
81
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"11:00:00", :estimated_time=>"11:00:00"}},
82
+ {:number=>43,
83
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"10:52:00", :estimated_time=>"10:52:00"},
84
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"10:52:00", :estimated_time=>"10:52:00"}},
85
+ {:number=>91,
86
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"11:02:00", :estimated_time=>"11:02:00"},
87
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"11:02:00", :estimated_time=>"11:02:00"}},
88
+ {:number=>125,
89
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"11:35:00", :estimated_time=>"11:35:00"},
90
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"11:35:00", :estimated_time=>"11:35:00"}},
91
+ {:number=>2117,
92
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"12:00:00", :estimated_time=>"12:00:00"},
93
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"12:00:00", :estimated_time=>"12:00:00"}},
94
+ {:number=>645,
95
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"12:05:00", :estimated_time=>"12:05:00"},
96
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"12:05:00", :estimated_time=>"12:05:00"}},
97
+ {:number=>171,
98
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"12:35:00", :estimated_time=>"12:35:00"},
99
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"12:35:00", :estimated_time=>"12:35:00"}},
100
+ {:number=>2159,
101
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"13:00:00", :estimated_time=>"13:00:00"},
102
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"13:00:00", :estimated_time=>"13:00:00"}},
103
+ {:number=>609,
104
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"12:54:00", :estimated_time=>"12:54:00"},
105
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"12:54:00", :estimated_time=>"12:54:00"}},
106
+ {:number=>2121,
107
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"14:00:00", :estimated_time=>"14:00:00"},
108
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"14:00:00", :estimated_time=>"14:00:00"}},
109
+ {:number=>93,
110
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"14:02:00", :estimated_time=>"14:02:00"},
111
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"14:02:00", :estimated_time=>"14:02:00"}},
112
+ {:number=>647,
113
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"14:11:00", :estimated_time=>"14:11:00"},
114
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"14:11:00", :estimated_time=>"14:11:00"}},
115
+ {:number=>19,
116
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"14:15:00", :estimated_time=>"14:15:00"},
117
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"14:15:00", :estimated_time=>"14:15:00"}},
118
+ {:number=>2163,
119
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"15:00:00", :estimated_time=>"15:00:00"},
120
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"15:00:00", :estimated_time=>"15:00:00"}},
121
+ {:number=>649,
122
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"14:44:00", :estimated_time=>"14:44:00"},
123
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"14:44:00", :estimated_time=>"14:44:00"}},
124
+ {:number=>85,
125
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"15:05:00", :estimated_time=>"15:05:00"},
126
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"15:05:00", :estimated_time=>"15:05:00"}},
127
+ {:number=>97,
128
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"15:15:00", :estimated_time=>"15:15:00"},
129
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"15:15:00", :estimated_time=>"15:15:00"}},
130
+ {:number=>173,
131
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"15:35:00", :estimated_time=>"15:35:00"},
132
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"15:35:00", :estimated_time=>"15:35:00"}},
133
+ {:number=>2165,
134
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"16:00:00", :estimated_time=>"16:00:00"},
135
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"16:00:00", :estimated_time=>"16:00:00"}},
136
+ {:number=>651,
137
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"16:03:00", :estimated_time=>"16:03:00"},
138
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"16:03:00", :estimated_time=>"16:03:00"}},
139
+ {:number=>127,
140
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"16:05:00", :estimated_time=>"16:05:00"},
141
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"16:05:00", :estimated_time=>"16:05:00"}},
142
+ {:number=>129,
143
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"16:42:00", :estimated_time=>"16:42:00"},
144
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"16:42:00", :estimated_time=>"16:42:00"}},
145
+ {:number=>2167,
146
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"17:00:00", :estimated_time=>"17:00:00"},
147
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"17:00:00", :estimated_time=>"17:00:00"}},
148
+ {:number=>653,
149
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"17:10:00", :estimated_time=>"17:10:00"},
150
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"17:10:00", :estimated_time=>"17:10:00"}},
151
+ {:number=>193,
152
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"17:39:00", :estimated_time=>"17:39:00"},
153
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"17:39:00", :estimated_time=>"17:39:00"}},
154
+ {:number=>2119,
155
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"18:00:00", :estimated_time=>"18:00:00"},
156
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"18:00:00", :estimated_time=>"18:00:00"}},
157
+ {:number=>137,
158
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"18:25:00", :estimated_time=>"18:25:00"},
159
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"18:25:00", :estimated_time=>"18:25:00"}},
160
+ {:number=>655,
161
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"18:35:00", :estimated_time=>"18:35:00"},
162
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"18:35:00", :estimated_time=>"18:35:00"}},
163
+ {:number=>2171,
164
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"19:00:00", :estimated_time=>"19:00:00"},
165
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"19:00:00", :estimated_time=>"19:00:00"}},
166
+ {:number=>55,
167
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"18:45:00", :estimated_time=>"18:45:00"},
168
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"18:45:00", :estimated_time=>"18:45:00"}},
169
+ {:number=>175,
170
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"19:40:00", :estimated_time=>"19:40:00"},
171
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"19:40:00", :estimated_time=>"19:40:00"}},
172
+ {:number=>2173,
173
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"20:13:00", :estimated_time=>"20:13:00"},
174
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"20:13:00", :estimated_time=>"20:13:00"}},
175
+ {:number=>2175,
176
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"21:05:00", :estimated_time=>"21:05:00"},
177
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"21:05:00", :estimated_time=>"21:05:00"}},
178
+ {:number=>187,
179
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"21:10:00", :estimated_time=>"21:10:00"},
180
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"21:10:00", :estimated_time=>"21:10:00"}},
181
+ {:number=>177,
182
+ :departure=>{:date=>"2017-10-12", :scheduled_time=>"22:05:00", :estimated_time=>"22:05:00"},
183
+ :arrival=>{:date=>"2017-10-12", :scheduled_time=>"22:05:00", :estimated_time=>"22:05:00"}}]
184
+ ```
2
185
 
3
- Pulls down the train times from the Amtrak website
data/amtrak.gemspec CHANGED
@@ -17,13 +17,12 @@ Gem::Specification.new do |spec|
17
17
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
18
  spec.require_paths = ['lib']
19
19
 
20
- spec.add_dependency 'mechanize', '~> 2.7'
21
- spec.add_dependency 'nokogiri', '~> 1.6.4'
20
+ spec.add_dependency 'excon', '~> 0.59'
22
21
 
23
22
  spec.add_development_dependency 'rake'
24
23
  spec.add_development_dependency 'pry'
25
- spec.add_development_dependency 'rspec', '~> 3.0.0'
26
- spec.add_development_dependency 'rubocop', '~> 0.25.0'
24
+ spec.add_development_dependency 'rspec'
25
+ spec.add_development_dependency 'rubocop'
27
26
  spec.add_development_dependency 'simplecov', '~> 0.8.2'
28
27
  spec.add_development_dependency 'vcr', '~> 2.9.2'
29
28
  spec.add_development_dependency 'webmock', '~> 1.24'
data/lib/amtrak.rb CHANGED
@@ -9,9 +9,8 @@ module Amtrak
9
9
  end
10
10
 
11
11
  def self.get(from, to, date: nil)
12
- Amtrak::TrainFetcher.get(from, to, date: date).map do |html|
13
- Amtrak::TrainParser.parse(html)
14
- end.flatten
12
+ json = Amtrak::TrainFetcher.get(from, to, date: date)
13
+ Amtrak::TrainParser.parse(json)
15
14
  end
16
15
  end
17
16
 
@@ -1,10 +1,9 @@
1
- require 'mechanize'
1
+ require 'json'
2
+ require 'excon'
2
3
 
3
4
  module Amtrak
4
5
  # Service for getting train time HTML page from the Amtrak website
5
6
  class TrainFetcher
6
- class Error < Amtrak::Error; end
7
-
8
7
  def self.get(*args)
9
8
  new(*args).get
10
9
  end
@@ -14,7 +13,7 @@ module Amtrak
14
13
  def initialize(from, to, date: nil)
15
14
  @from = from
16
15
  @to = to
17
- @date = date
16
+ @date = date || Date.today
18
17
  end
19
18
 
20
19
  def check_release
@@ -22,36 +21,34 @@ module Amtrak
22
21
  end
23
22
 
24
23
  def get
25
- requests = [first_page.body]
26
-
27
- (2..total_pages).each do |page|
28
- requests << Amtrak::TrainFetcher::TrainPage.get(agent, page)
29
- end
30
-
31
- requests
24
+ JSON.parse(response.body)
32
25
  end
33
26
 
34
- def first_page
35
- @first_page ||= Amtrak::TrainFetcher::MainPage.new(agent, from, to, date: date)
36
- end
27
+ private
37
28
 
38
- def total_pages
39
- return @total_pages if @total_pages
40
-
41
- total_pages = first_page.total_pages
42
- Amtrak.logger.debug "Total pages: #{total_pages}"
29
+ def response
30
+ Excon.post(
31
+ 'https://rider.amtrak.com/MobileApps/TrainStatus',
32
+ body: body.to_json,
33
+ headers: headers
34
+ )
35
+ end
43
36
 
44
- @total_pages = total_pages
37
+ def body
38
+ {
39
+ 'dateTime' => date.strftime('%Y-%0m-%d'),
40
+ 'origin' => from.upcase,
41
+ 'destination' => to.upcase,
42
+ 'type' => 'A',
43
+ 'versionNumber' => '2.2.12'
44
+ }
45
45
  end
46
46
 
47
- def agent
48
- @agent ||= Mechanize.new.tap do |m|
49
- m.user_agent_alias = 'Mac Safari'
50
- m.log = Amtrak.logger
51
- end
47
+ def headers
48
+ {
49
+ 'Accept' => '*/*',
50
+ 'Content-Type' => 'application/json'
51
+ }
52
52
  end
53
53
  end
54
54
  end
55
-
56
- require 'amtrak/train_fetcher/main_page'
57
- require 'amtrak/train_fetcher/train_page'
@@ -1,92 +1,40 @@
1
- require 'nokogiri'
2
-
3
1
  module Amtrak
4
- # Will take in an HTML document as a string and parse out the train schedule
2
+ # Will take in an JSON document as a hash and parse out the train schedule
5
3
  class TrainParser
6
4
  # Error raised when the parser runs into an issue
7
5
  class Error < Amtrak::Error; end
8
6
 
9
- def self.parse(text)
10
- new(text).parse
7
+ def self.parse(json)
8
+ new(json).parse
11
9
  end
12
10
 
13
- attr_reader :document
11
+ attr_reader :json
14
12
 
15
- def initialize(document)
16
- @document = Nokogiri::HTML.parse(document)
13
+ def initialize(json)
14
+ @json = json
17
15
  end
18
16
 
19
17
  def parse
20
- trains = []
21
-
22
- while train_node = train_nodes.shift
23
- cancelled = cancelled?(train_node)
24
- trains << {
25
- number: parse_train_number(train_node),
26
- departure: parse_train(find_depart_status(train_node), cancelled),
27
- arrival: parse_train(find_arrive_status(train_node), cancelled)
28
- }
29
- end
30
-
31
- trains
32
- rescue Nokogiri::SyntaxError => ex
33
- raise Amtrak::TrainParser::Error, "#{ex.class} #{ex.message}"
34
- end
35
-
36
- def train_nodes
37
- @train_nodes ||= document.search(
38
- "//div[@id='train_status_resp_by_citypair']"
39
- ).to_a
40
- end
41
-
42
- def cancelled?(node)
43
- node.search(".//div[@class='cancelledMsg']").count > 0
44
- end
45
-
46
- def find_depart_status(node)
47
- find!(node, ".//div[@id='resp_by_citypair_depart_status_details']")
48
- end
49
-
50
- def find_arrive_status(node)
51
- find!(node, ".//div[@id='resp_by_citypair_arrive_status_details']")
52
- end
53
-
54
- def parse_train_number(node)
55
- number = parse_train_number_25(node)
56
- return number unless number.zero?
57
-
58
- parse_train_number_22(node)
18
+ json['journeys']
19
+ .map(&method(:parse_journey))
20
+ .compact
59
21
  end
60
22
 
61
- def parse_train_number_25(node)
62
- find!(
63
- node,
64
- ".//div[@id='resp_by_citypair_subheading']/\
65
- div[@id='resp_by_citypair_subheading_trainname']/div/text()"
66
- ).to_s.to_i
67
- end
23
+ def parse_journey(journey)
24
+ segment = journey['segments'].first
25
+ return unless segment
68
26
 
69
- def parse_train_number_22(node)
70
- node.search(
71
- ".//div[@id='resp_by_citypair_subheading']/\
72
- div[@id='resp_by_citypair_subheading_trainname']/text()"
73
- ).first.to_s.to_i
27
+ {
28
+ number: segment['trainNumber'].to_i,
29
+ departure: find_departure_times(segment),
30
+ arrival: find_arrival_times(segment)
31
+ }
74
32
  end
75
33
 
76
- def parse_train(node, cancelled) # rubocop:disable Metrics/MethodLength
77
- date = find!(
78
- node, ".//div[@class='arriveDepartDate']/text()"
79
- ).to_s
80
- if cancelled
81
- estimated_time = scheduled_time = 'Cancelled'
82
- else
83
- scheduled_time = clean_msg(
84
- find!(node, ".//div[@class='scheduledArriveDepartMsg']/text()").to_s
85
- )
86
- estimated_time = find(
87
- node, ".//div[@class='arriveDepartTime']/text()"
88
- ).to_s
89
- end
34
+ def find_departure_times(segment)
35
+ date, scheduled_time = segment['originScheduledDepartureDateTime'].split('T')
36
+ estimated_depart = segment['originEstimatedDepartureDateTime']
37
+ _, estimated_time = estimated_depart.split('T') if estimated_depart
90
38
 
91
39
  {
92
40
  date: date,
@@ -95,20 +43,16 @@ module Amtrak
95
43
  }
96
44
  end
97
45
 
98
- def find!(node, xpath)
99
- node.search(xpath).tap { |rs| fail "#{rs.count} results" if rs.count > 1 }
100
- end
101
-
102
- def find(node, xpath)
103
- find!(node, xpath)
104
- rescue RuntimeError
105
- nil
106
- end
46
+ def find_arrival_times(segment)
47
+ date, scheduled_time = segment['originScheduledDepartureDateTime'].split('T')
48
+ estimated_arrival = segment['originEstimatedDepartureDateTime']
49
+ _, estimated_time = estimated_arrival.split('T') if estimated_arrival
107
50
 
108
- def clean_msg(time_msg)
109
- return unless matches = /\d+:\d+ (a|p)m/.match(time_msg)
110
-
111
- matches[0]
51
+ {
52
+ date: date,
53
+ scheduled_time: scheduled_time,
54
+ estimated_time: estimated_time
55
+ }
112
56
  end
113
57
  end
114
58
  end