rail_feeds 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +8 -1
- data/.travis.yml +17 -4
- data/CHANGELOG.md +12 -0
- data/README.md +11 -7
- data/doc/guides/National Rail/Knowledge Base/National Service Indicator.md +21 -0
- data/doc/guides/Network Rail/CORPUS.md +7 -3
- data/doc/guides/Network Rail/SMART.md +6 -2
- data/doc/guides/Network Rail/Schedule.md +4 -4
- data/lib/rail_feeds/credentials.rb +30 -0
- data/lib/rail_feeds/http_client.rb +56 -0
- data/lib/rail_feeds/logging.rb +0 -2
- data/lib/rail_feeds/national_rail/credentials.rb +11 -0
- data/lib/rail_feeds/national_rail/http_client.rb +45 -0
- data/lib/rail_feeds/national_rail/knowledge_base/national_service_indicator.rb +100 -0
- data/lib/rail_feeds/national_rail/knowledge_base.rb +8 -0
- data/lib/rail_feeds/national_rail.rb +9 -0
- data/lib/rail_feeds/network_rail/corpus.rb +5 -6
- data/lib/rail_feeds/network_rail/credentials.rb +0 -11
- data/lib/rail_feeds/network_rail/http_client.rb +8 -44
- data/lib/rail_feeds/network_rail/schedule/association.rb +2 -2
- data/lib/rail_feeds/network_rail/schedule/data.rb +3 -2
- data/lib/rail_feeds/network_rail/schedule/days.rb +1 -0
- data/lib/rail_feeds/network_rail/schedule/fetcher.rb +1 -2
- data/lib/rail_feeds/network_rail/schedule/header/json.rb +2 -2
- data/lib/rail_feeds/network_rail/schedule/header.rb +0 -3
- data/lib/rail_feeds/network_rail/schedule/parser/json.rb +0 -2
- data/lib/rail_feeds/network_rail/schedule/parser.rb +1 -4
- data/lib/rail_feeds/network_rail/schedule/tiploc.rb +2 -2
- data/lib/rail_feeds/network_rail/schedule/train_schedule/location.rb +1 -4
- data/lib/rail_feeds/network_rail/schedule/train_schedule.rb +8 -12
- data/lib/rail_feeds/network_rail/schedule.rb +3 -10
- data/lib/rail_feeds/network_rail/smart.rb +17 -17
- data/lib/rail_feeds/network_rail/stomp_client.rb +2 -3
- data/lib/rail_feeds/network_rail.rb +0 -7
- data/lib/rail_feeds/version.rb +1 -1
- data/lib/rail_feeds.rb +40 -4
- data/rail_feeds.gemspec +28 -23
- data/spec/rail_feeds/credentials_spec.rb +28 -1
- data/spec/rail_feeds/http_client_spec.rb +75 -0
- data/spec/rail_feeds/national_rail/credentials_spec.rb +13 -0
- data/spec/rail_feeds/national_rail/http_client_spec.rb +57 -0
- data/spec/rail_feeds/national_rail/knowledge_base/national_service_indicator_spec.rb +122 -0
- data/spec/rail_feeds/national_rail/knowledge_base_spec.rb +4 -0
- data/spec/rail_feeds/national_rail_spec.rb +7 -0
- data/spec/rail_feeds/network_rail/corpus_spec.rb +2 -2
- data/spec/rail_feeds/network_rail/credentials_spec.rb +3 -12
- data/spec/rail_feeds/network_rail/http_client_spec.rb +7 -75
- data/spec/rail_feeds/network_rail/schedule/data_spec.rb +1 -1
- data/spec/rail_feeds/network_rail/smart_spec.rb +2 -2
- data/spec/rail_feeds/network_rail/stomp_client_spec.rb +1 -1
- metadata +48 -9
- data/file +0 -0
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'net/http'
|
4
|
-
|
5
3
|
module RailFeeds
|
6
4
|
module NetworkRail
|
7
5
|
module Schedule
|
@@ -177,6 +175,7 @@ module RailFeeds
|
|
177
175
|
unless %w[mon tue wed thu fri sat sun].include?(day)
|
178
176
|
fail ArgumentError, 'day is invalid'
|
179
177
|
end
|
178
|
+
|
180
179
|
day = "toc-update-#{day}"
|
181
180
|
type = "CIF_#{toc}_UPDATE_DAILY"
|
182
181
|
end
|
@@ -49,7 +49,7 @@ module RailFeeds
|
|
49
49
|
end
|
50
50
|
|
51
51
|
# rubocop:disable Metrics/MethodLength
|
52
|
-
def to_json
|
52
|
+
def to_json(**opts)
|
53
53
|
{
|
54
54
|
'JsonTimetableV1' => {
|
55
55
|
'classification' => 'public',
|
@@ -65,7 +65,7 @@ module RailFeeds
|
|
65
65
|
'sequence' => sequence
|
66
66
|
}
|
67
67
|
}
|
68
|
-
}.to_json
|
68
|
+
}.to_json(**opts)
|
69
69
|
end
|
70
70
|
# rubocop:enable Metrics/MethodLength
|
71
71
|
|
@@ -1,8 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'parser/cif'
|
4
|
-
require_relative 'parser/json'
|
5
|
-
|
6
3
|
module RailFeeds
|
7
4
|
module NetworkRail
|
8
5
|
module Schedule
|
@@ -75,7 +72,7 @@ module RailFeeds
|
|
75
72
|
end
|
76
73
|
# rubocop:enable Metrics/ParameterLists
|
77
74
|
|
78
|
-
# Parse the data in
|
75
|
+
# Parse the data in file.
|
79
76
|
# @param [IO] file
|
80
77
|
# The file to load data from.
|
81
78
|
def parse_file(file)
|
@@ -81,7 +81,7 @@ module RailFeeds
|
|
81
81
|
].join) + "\n"
|
82
82
|
end
|
83
83
|
|
84
|
-
def to_json
|
84
|
+
def to_json(**opts)
|
85
85
|
{
|
86
86
|
'TiplocV1' => {
|
87
87
|
'transaction_type' => 'Create',
|
@@ -92,7 +92,7 @@ module RailFeeds
|
|
92
92
|
'description' => nlc_description,
|
93
93
|
'tps_description' => tps_description
|
94
94
|
}
|
95
|
-
}.to_json
|
95
|
+
}.to_json(**opts)
|
96
96
|
end
|
97
97
|
end
|
98
98
|
end
|
@@ -1,9 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'location/intermediate'
|
4
|
-
require_relative 'location/origin'
|
5
|
-
require_relative 'location/terminating'
|
6
|
-
|
7
3
|
module RailFeeds
|
8
4
|
module NetworkRail
|
9
5
|
module Schedule
|
@@ -65,6 +61,7 @@ module RailFeeds
|
|
65
61
|
|
66
62
|
def allowance_json(value)
|
67
63
|
return nil if value.nil?
|
64
|
+
|
68
65
|
i = value.to_i
|
69
66
|
f = value.to_f - i
|
70
67
|
f.eql?(0.5) ? "#{i}H" : i.to_s
|
@@ -1,11 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'date'
|
4
|
-
require 'time'
|
5
|
-
|
6
|
-
require_relative 'train_schedule/change_en_route'
|
7
|
-
require_relative 'train_schedule/location'
|
8
|
-
|
9
3
|
module RailFeeds
|
10
4
|
module NetworkRail
|
11
5
|
module Schedule
|
@@ -181,7 +175,7 @@ module RailFeeds
|
|
181
175
|
|
182
176
|
# rubocop:disable Metrics/AbcSize
|
183
177
|
# rubocop:disable Metrics/MethodLength
|
184
|
-
def to_json
|
178
|
+
def to_json(**opts)
|
185
179
|
{
|
186
180
|
'JsonScheduleV1' => {
|
187
181
|
'CIF_bank_holiday_running' => bank_holiday_running,
|
@@ -218,7 +212,7 @@ module RailFeeds
|
|
218
212
|
'schedule_location' => journey.map(&:to_hash_for_json).reject(&:nil?)
|
219
213
|
}
|
220
214
|
}
|
221
|
-
}.to_json
|
215
|
+
}.to_json(**opts)
|
222
216
|
end
|
223
217
|
# rubocop:enable Metrics/AbcSize
|
224
218
|
# rubocop:enable Metrics/MethodLength
|
@@ -318,10 +312,11 @@ module RailFeeds
|
|
318
312
|
end
|
319
313
|
|
320
314
|
def self.location_from_json(hash)
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
315
|
+
case hash['record_identity']
|
316
|
+
when 'LO' then lo_from_json(hash)
|
317
|
+
when 'LI' then li_from_json(hash)
|
318
|
+
when 'LT' then lt_from_json(hash)
|
319
|
+
end
|
325
320
|
end
|
326
321
|
private_class_method :location_from_json
|
327
322
|
|
@@ -380,6 +375,7 @@ module RailFeeds
|
|
380
375
|
|
381
376
|
def self.parse_allowance(value)
|
382
377
|
return nil if value.nil? || value.empty?
|
378
|
+
|
383
379
|
half = value[-1].eql?('H')
|
384
380
|
value = value.to_f
|
385
381
|
half ? value + 0.5 : value
|
@@ -1,31 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'schedule/days'
|
4
|
-
require_relative 'schedule/stp_indicator'
|
5
|
-
require_relative 'schedule/association'
|
6
|
-
require_relative 'schedule/header'
|
7
|
-
require_relative 'schedule/tiploc'
|
8
|
-
require_relative 'schedule/train_schedule'
|
9
|
-
require_relative 'schedule/fetcher'
|
10
|
-
require_relative 'schedule/parser'
|
11
|
-
require_relative 'schedule/data'
|
12
|
-
|
13
3
|
module RailFeeds
|
14
4
|
module NetworkRail
|
15
5
|
module Schedule # :nodoc:
|
16
6
|
def self.nil_or_i(value)
|
17
7
|
return nil if value.to_s.strip.empty?
|
8
|
+
|
18
9
|
value.to_i
|
19
10
|
end
|
20
11
|
|
21
12
|
def self.nil_or_strip(value)
|
22
13
|
return nil if value.to_s.strip.empty?
|
14
|
+
|
23
15
|
value.strip
|
24
16
|
end
|
25
17
|
|
26
18
|
def self.make_date(value, allow_nil: false)
|
27
19
|
return nil if allow_nil && value.strip.empty?
|
28
20
|
return Date.new(9999, 12, 31) if value.eql?('999999')
|
21
|
+
|
29
22
|
Date.strptime(value, '%y%m%d')
|
30
23
|
end
|
31
24
|
end
|
@@ -1,8 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'json'
|
4
|
-
require 'set'
|
5
|
-
|
6
3
|
module RailFeeds
|
7
4
|
module NetworkRail
|
8
5
|
# rubocop:disable Metrics/ModuleLength
|
@@ -16,6 +13,7 @@ module RailFeeds
|
|
16
13
|
def from_direction
|
17
14
|
return :up if event_direction.eql?(:down)
|
18
15
|
return :down if event_direction.eql?(:up)
|
16
|
+
|
19
17
|
nil
|
20
18
|
end
|
21
19
|
|
@@ -32,15 +30,15 @@ module RailFeeds
|
|
32
30
|
# @param [RailFeeds::NetworkRail::Credentials] credentials
|
33
31
|
# @param [String] file
|
34
32
|
# The path to the file to save the .json.gz download in.
|
35
|
-
def self.download(file, credentials
|
33
|
+
def self.download(file, credentials = Credentials)
|
36
34
|
client = HTTPClient.new(credentials: credentials)
|
37
35
|
client.download 'ntrod/SupportingFileAuthenticate?type=SMART', file
|
38
36
|
end
|
39
37
|
|
40
38
|
# Fetch the current SMART data.
|
41
39
|
# @param [RailFeeds::NetworkRail::Credentials] credentials
|
42
|
-
# @return [
|
43
|
-
def self.fetch(credentials
|
40
|
+
# @return [IO]
|
41
|
+
def self.fetch(credentials = Credentials)
|
44
42
|
client = HTTPClient.new(credentials: credentials)
|
45
43
|
client.fetch 'ntrod/SupportingFileAuthenticate?type=SMART'
|
46
44
|
end
|
@@ -60,7 +58,7 @@ module RailFeeds
|
|
60
58
|
# @param [RailFeeds::NetworkRail::Credentials] credentials
|
61
59
|
# The credentials to authenticate with.
|
62
60
|
# @return [Array<RailFeeds::NetworkRail::SMART::Step>]
|
63
|
-
def self.fetch_data(credentials
|
61
|
+
def self.fetch_data(credentials = Credentials)
|
64
62
|
client = HTTPClient.new(credentials: credentials)
|
65
63
|
client.fetch_unzipped('ntrod/SupportingFileAuthenticate?type=SMART') do |file|
|
66
64
|
break parse_json file.read
|
@@ -147,6 +145,7 @@ module RailFeeds
|
|
147
145
|
|
148
146
|
def self.nilify(value)
|
149
147
|
return nil if value.nil? || value.empty?
|
148
|
+
|
150
149
|
value
|
151
150
|
end
|
152
151
|
private_class_method :nilify
|
@@ -154,6 +153,7 @@ module RailFeeds
|
|
154
153
|
def self.event_type(value)
|
155
154
|
return :arrive if value.eql?('A') || value.eql?('C')
|
156
155
|
return :depart if value.eql?('B') || value.eql?('D')
|
156
|
+
|
157
157
|
nil
|
158
158
|
end
|
159
159
|
private_class_method :event_type
|
@@ -161,24 +161,24 @@ module RailFeeds
|
|
161
161
|
def self.event_direction(value)
|
162
162
|
return :up if value.eql?('A') || value.eql?('B')
|
163
163
|
return :down if value.eql?('C') || value.eql?('D')
|
164
|
+
|
164
165
|
nil
|
165
166
|
end
|
166
167
|
private_class_method :event_direction
|
167
168
|
|
168
169
|
# rubocop:disable Metrics/CyclomaticComplexity
|
169
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
170
170
|
def self.step_type(value)
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
171
|
+
case value
|
172
|
+
when 'B' then :between
|
173
|
+
when 'F' then :from
|
174
|
+
when 'T' then :to
|
175
|
+
when 'D' then :intermediate_first
|
176
|
+
when 'E' then :intermediate
|
177
|
+
when 'C' then :clearout
|
178
|
+
when 'I' then :interpose
|
179
|
+
end
|
179
180
|
end
|
180
181
|
# rubocop:enable Metrics/CyclomaticComplexity
|
181
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
182
182
|
private_class_method :step_type
|
183
183
|
end
|
184
184
|
# rubocop:enable Metrics/ModuleLength
|
@@ -1,8 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'socket'
|
4
|
-
require 'stomp'
|
5
|
-
|
6
3
|
module RailFeeds
|
7
4
|
module NetworkRail
|
8
5
|
# A wrapper class for ::Stomp::Client which provides durable subscriptions
|
@@ -27,6 +24,7 @@ module RailFeeds
|
|
27
24
|
# Connect to the network rail server.
|
28
25
|
def connect
|
29
26
|
return if @client && client.open?
|
27
|
+
|
30
28
|
client_options = {
|
31
29
|
hosts: [{
|
32
30
|
host: HOST,
|
@@ -49,6 +47,7 @@ module RailFeeds
|
|
49
47
|
# Disconnect from the network rail server.
|
50
48
|
def disconnect
|
51
49
|
return if @client.nil?
|
50
|
+
|
52
51
|
@client.close
|
53
52
|
end
|
54
53
|
|
@@ -1,12 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'network_rail/credentials'
|
4
|
-
require_relative 'network_rail/http_client'
|
5
|
-
require_relative 'network_rail/stomp_client'
|
6
|
-
require_relative 'network_rail/corpus'
|
7
|
-
require_relative 'network_rail/schedule'
|
8
|
-
require_relative 'network_rail/smart'
|
9
|
-
|
10
3
|
module RailFeeds
|
11
4
|
module NetworkRail # :nodoc:
|
12
5
|
end
|
data/lib/rail_feeds/version.rb
CHANGED
data/lib/rail_feeds.rb
CHANGED
@@ -1,10 +1,46 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
module RailFeeds # :nodoc:
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'date'
|
7
|
+
require 'forwardable'
|
8
|
+
require 'logger'
|
9
|
+
|
10
|
+
require 'nokogiri'
|
11
|
+
require 'stomp'
|
4
12
|
|
13
|
+
require_relative 'rail_feeds/version'
|
5
14
|
require_relative 'rail_feeds/logging'
|
6
15
|
require_relative 'rail_feeds/credentials'
|
16
|
+
require_relative 'rail_feeds/http_client'
|
17
|
+
require_relative 'rail_feeds/national_rail'
|
18
|
+
require_relative 'rail_feeds/national_rail/credentials'
|
19
|
+
require_relative 'rail_feeds/national_rail/http_client'
|
20
|
+
require_relative 'rail_feeds/national_rail/knowledge_base'
|
21
|
+
require_relative 'rail_feeds/national_rail/knowledge_base/national_service_indicator'
|
7
22
|
require_relative 'rail_feeds/network_rail'
|
8
|
-
|
9
|
-
|
10
|
-
|
23
|
+
require_relative 'rail_feeds/network_rail/credentials'
|
24
|
+
require_relative 'rail_feeds/network_rail/http_client'
|
25
|
+
require_relative 'rail_feeds/network_rail/stomp_client'
|
26
|
+
require_relative 'rail_feeds/network_rail/corpus'
|
27
|
+
require_relative 'rail_feeds/network_rail/smart'
|
28
|
+
require_relative 'rail_feeds/network_rail/schedule'
|
29
|
+
require_relative 'rail_feeds/network_rail/schedule/days'
|
30
|
+
require_relative 'rail_feeds/network_rail/schedule/stp_indicator'
|
31
|
+
require_relative 'rail_feeds/network_rail/schedule/association'
|
32
|
+
require_relative 'rail_feeds/network_rail/schedule/data'
|
33
|
+
require_relative 'rail_feeds/network_rail/schedule/fetcher'
|
34
|
+
require_relative 'rail_feeds/network_rail/schedule/tiploc'
|
35
|
+
require_relative 'rail_feeds/network_rail/schedule/header'
|
36
|
+
require_relative 'rail_feeds/network_rail/schedule/header/cif'
|
37
|
+
require_relative 'rail_feeds/network_rail/schedule/header/json'
|
38
|
+
require_relative 'rail_feeds/network_rail/schedule/parser'
|
39
|
+
require_relative 'rail_feeds/network_rail/schedule/parser/cif'
|
40
|
+
require_relative 'rail_feeds/network_rail/schedule/parser/json'
|
41
|
+
require_relative 'rail_feeds/network_rail/schedule/train_schedule'
|
42
|
+
require_relative 'rail_feeds/network_rail/schedule/train_schedule/change_en_route'
|
43
|
+
require_relative 'rail_feeds/network_rail/schedule/train_schedule/location'
|
44
|
+
require_relative 'rail_feeds/network_rail/schedule/train_schedule/location/intermediate'
|
45
|
+
require_relative 'rail_feeds/network_rail/schedule/train_schedule/location/origin'
|
46
|
+
require_relative 'rail_feeds/network_rail/schedule/train_schedule/location/terminating'
|
data/rail_feeds.gemspec
CHANGED
@@ -3,30 +3,35 @@
|
|
3
3
|
$LOAD_PATH.push File.expand_path('lib', __dir__)
|
4
4
|
require File.join(File.dirname(__FILE__), 'lib', 'rail_feeds', 'version')
|
5
5
|
|
6
|
-
Gem::Specification.new do |
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = 'rail_feeds'
|
8
|
+
gem.license = 'BSD 3 clause'
|
9
|
+
gem.version = RailFeeds::Version
|
10
|
+
gem.authors = ['Robert Gauld']
|
11
|
+
gem.email = ['robert@robertgauld.co.uk']
|
12
|
+
gem.homepage = 'https://github.com/robertgauld/rail_feeds'
|
13
|
+
gem.summary = 'Make use of the various open data rails feeds in the UK.'
|
14
|
+
gem.description = 'Make use of the various open data rails feeds in the UK. Currently only some from Network Rail.'
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
gem.files = `git ls-files`.split("\n")
|
17
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
19
|
+
gem.require_paths = ['lib']
|
20
20
|
|
21
|
-
|
21
|
+
gem.required_ruby_version = '>= 2.4'
|
22
|
+
gem.required_rubygems_version = '>= 2.6.14'
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
24
|
+
gem.add_dependency 'nokogiri', '~> 1.8'
|
25
|
+
gem.add_dependency 'stomp', '~> 1.4'
|
26
|
+
|
27
|
+
gem.add_development_dependency 'coveralls', '~> 0.7'
|
28
|
+
gem.add_development_dependency 'guard-rspec', '~> 4.2', '>= 4.2.5'
|
29
|
+
gem.add_development_dependency 'guard-rubocop', '~> 1.3'
|
30
|
+
gem.add_development_dependency 'rake', '~> 12.0'
|
31
|
+
gem.add_development_dependency 'rb-inotify', '~> 0.9'
|
32
|
+
gem.add_development_dependency 'rspec', '>= 3.7', '< 4'
|
33
|
+
gem.add_development_dependency 'rubocop', '~> 0.67'
|
34
|
+
gem.add_development_dependency 'rubocop-performance', '~> 1.1'
|
35
|
+
gem.add_development_dependency 'simplecov', '~> 0.7'
|
36
|
+
gem.add_development_dependency 'timecop', '~> 0.5'
|
32
37
|
end
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
describe RailFeeds::Credentials do
|
4
4
|
context 'Using system wide credentials' do
|
5
|
+
subject { described_class.new }
|
6
|
+
|
5
7
|
before :each do
|
6
8
|
described_class.configure(
|
7
9
|
username: 'user@example.com',
|
@@ -20,7 +22,6 @@ describe RailFeeds::Credentials do
|
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
23
|
-
|
24
25
|
context 'Using specific credentials' do
|
25
26
|
subject do
|
26
27
|
described_class.new(
|
@@ -43,4 +44,30 @@ describe RailFeeds::Credentials do
|
|
43
44
|
expect(described_class.password).to eq ''
|
44
45
|
end
|
45
46
|
end
|
47
|
+
|
48
|
+
describe 'Outputs an array' do
|
49
|
+
subject { described_class.new username: 'user-i', password: 'pass-i' }
|
50
|
+
|
51
|
+
it '::to_a' do
|
52
|
+
described_class.configure username: 'user', password: 'pass'
|
53
|
+
expect(described_class.to_a).to eq ['user', 'pass']
|
54
|
+
end
|
55
|
+
|
56
|
+
it '#to_a' do
|
57
|
+
expect(subject.to_a).to eq ['user-i', 'pass-i']
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe 'Outputs a hash' do
|
62
|
+
subject { described_class.new username: 'user-i', password: 'pass-i' }
|
63
|
+
|
64
|
+
it '::to_h' do
|
65
|
+
described_class.configure username: 'user', password: 'pass'
|
66
|
+
expect(described_class.to_h).to eq({ username: 'user', password: 'pass' })
|
67
|
+
end
|
68
|
+
|
69
|
+
it '#to_h' do
|
70
|
+
expect(subject.to_h).to eq({ username: 'user-i', password: 'pass-i' })
|
71
|
+
end
|
72
|
+
end
|
46
73
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe RailFeeds::HTTPClient do
|
4
|
+
let(:temp_file) { double Tempfile }
|
5
|
+
let(:uri) { double URI }
|
6
|
+
|
7
|
+
describe '#download' do
|
8
|
+
let(:file) { double File }
|
9
|
+
|
10
|
+
it 'Saves the file' do
|
11
|
+
expect(subject).to receive(:fetch).with('url').and_yield(temp_file)
|
12
|
+
expect(File).to receive(:open).with('file', 'w').and_yield(file)
|
13
|
+
expect(IO).to receive(:copy_stream).with(temp_file, file)
|
14
|
+
subject.download('url', 'file')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#fetch' do
|
19
|
+
describe 'Yields an IO' do
|
20
|
+
it 'When uri.open gives a TempFile' do
|
21
|
+
expect(URI).to receive(:parse).with('https://www.example.com/path').and_return(uri)
|
22
|
+
expect(uri).to receive(:open).and_return(temp_file)
|
23
|
+
expect { |a| subject.fetch('https://www.example.com/path', &a) }.to yield_with_args(temp_file)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'When uri.open gives a StringIO' do
|
27
|
+
string_io = double StringIO
|
28
|
+
expect(URI).to receive(:parse).with('https://www.example.com/path').and_return(uri)
|
29
|
+
expect(uri).to receive(:open).and_return(string_io)
|
30
|
+
expect { |a| subject.fetch('https://www.example.com/path', &a) }.to yield_with_args(string_io)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'Adds credentials when getting path' do
|
35
|
+
credentials = RailFeeds::NetworkRail::Credentials.new(
|
36
|
+
username: 'user',
|
37
|
+
password: 'pass'
|
38
|
+
)
|
39
|
+
expect(URI).to receive(:parse).and_return(uri)
|
40
|
+
expect(uri).to receive(:open)
|
41
|
+
.with(http_basic_authentication: ['user', 'pass'])
|
42
|
+
.and_return(temp_file)
|
43
|
+
subject = described_class.new credentials: credentials
|
44
|
+
subject.fetch('path') {}
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'Handles special characters in credentials' do
|
48
|
+
credentials = RailFeeds::NetworkRail::Credentials.new(
|
49
|
+
username: 'a@example.com',
|
50
|
+
password: '!:@'
|
51
|
+
)
|
52
|
+
expect(URI).to receive(:parse).and_return(uri)
|
53
|
+
expect(uri).to receive(:open).and_return(temp_file)
|
54
|
+
subject = described_class.new credentials: credentials
|
55
|
+
expect { subject.fetch('path') {} }.to_not raise_error
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'Passes extra options on' do
|
59
|
+
expect(URI).to receive(:parse).and_return(uri)
|
60
|
+
expect(uri).to receive(:open)
|
61
|
+
.with({ a: 'a', http_basic_authentication: [] })
|
62
|
+
.and_return(temp_file)
|
63
|
+
subject.fetch('path', { a: 'a' }) {}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe '#fetch_unzipped' do
|
68
|
+
it 'Returns what Zlib::GzipReader.open does' do
|
69
|
+
reader = double Zlib::GzipReader
|
70
|
+
expect(subject).to receive(:fetch).with('url').and_yield(temp_file)
|
71
|
+
expect(Zlib::GzipReader).to receive(:new).with(temp_file).and_return(reader)
|
72
|
+
expect { |a| subject.fetch_unzipped('url', &a) }.to yield_with_args(reader)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe RailFeeds::NationalRail::Credentials do
|
4
|
+
it 'Is a RailFeeds::Credentials' do
|
5
|
+
expect(described_class).to be < RailFeeds::Credentials
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'Has seperate values to RailFeeds::Credentials' do
|
9
|
+
described_class.configure username: 'a', password: 'b'
|
10
|
+
expect(described_class.username).to_not eq RailFeeds::Credentials.username
|
11
|
+
expect(described_class.password).to_not eq RailFeeds::Credentials.password
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe RailFeeds::NationalRail::HTTPClient do
|
4
|
+
let(:uri) { double URI }
|
5
|
+
|
6
|
+
it 'Is a RailFeeds::HTTPClient' do
|
7
|
+
expect(described_class).to be < RailFeeds::HTTPClient
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'has correct default credentials' do
|
11
|
+
expect(subject.send(:credentials)).to eq RailFeeds::NationalRail::Credentials
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#fetch' do
|
15
|
+
context 'Gets an auth token when' do
|
16
|
+
before(:each) { allow(uri).to receive(:open) }
|
17
|
+
|
18
|
+
it 'It has not been fetched yet' do
|
19
|
+
expect(subject).to receive(:auth_token)
|
20
|
+
expect(URI).to receive(:parse).with('https://datafeeds.nationalrail.co.uk/path').and_return(uri)
|
21
|
+
subject.fetch('path') {}
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'Token is over an hour old' do
|
25
|
+
expect(subject).to receive(:auth_token).twice
|
26
|
+
expect(URI).to receive(:parse).with('https://datafeeds.nationalrail.co.uk/path')
|
27
|
+
.and_return(uri).twice
|
28
|
+
subject.fetch('path') {} # Get the auth token
|
29
|
+
Timecop.travel 3601
|
30
|
+
subject.fetch('path') {} # Token expired so should reget it
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'Getting the token' do
|
34
|
+
subject = described_class.new(credentials: RailFeeds::Credentials.new(username: '', password: ''))
|
35
|
+
response = double Net::HTTPCreated
|
36
|
+
expect(response).to receive(:value)
|
37
|
+
expect(response).to receive(:body).and_return('{"token":"TOKEN"}')
|
38
|
+
expect(Net::HTTP).to receive(:post_form)
|
39
|
+
.with(URI('https://datafeeds.nationalrail.co.uk/authenticate'), { username: '', password: '' })
|
40
|
+
.and_return(response)
|
41
|
+
expect(subject.send(:auth_token)).to eq 'TOKEN'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'Has a valid auth_token' do
|
46
|
+
before :each do
|
47
|
+
allow(subject).to receive(:auth_token).and_return('auth_token')
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'Adds server to path then delegates to super' do
|
51
|
+
expect(URI).to receive(:parse).with('https://datafeeds.nationalrail.co.uk/path').and_return(uri)
|
52
|
+
expect(uri).to receive(:open)
|
53
|
+
subject.fetch('path') {}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|