amtrak 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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