rail_feeds 0.0.1 → 0.0.2
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.
- 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
|