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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 48c8d73c18dddf2cbe0cdc89764f686112157e85b910ac07140a0718871aa20b
|
4
|
+
data.tar.gz: e27ab1045735dc9e1c69419821af37610c6234ca9ceda8fb7664614e3abdbafd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 58fb1b17bd665d1d1881d143bccbc5f1ee1a743710b28ecd8f88867b52ee4e238bcc438072425bf3098e3142769a9e671aea74796629c5015b82a0bb35c95770
|
7
|
+
data.tar.gz: 0ea4810aa3c8d91de9e7e0a6fad6adf26a7c4c7fbdb35c6a41e9bd47ad365b91be3e9de3ac7ac50baa416edadfa9231703bf25ba66a9085f5c359274fd7d3b7c
|
data/.rubocop.yml
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
+
require:
|
2
|
+
- rubocop-performance
|
1
3
|
AllCops:
|
2
|
-
TargetRubyVersion: 2.
|
4
|
+
TargetRubyVersion: 2.4
|
5
|
+
Exclude:
|
6
|
+
- '*.gemspec'
|
3
7
|
Style/SignalException:
|
4
8
|
Enabled: false
|
5
9
|
Metrics/MethodLength:
|
@@ -14,6 +18,9 @@ Metrics/LineLength:
|
|
14
18
|
Layout/TrailingBlankLines:
|
15
19
|
Exclude:
|
16
20
|
- rail_feeds.gemspec
|
21
|
+
Style/BracesAroundHashParameters:
|
22
|
+
Exclude:
|
23
|
+
- spec/**/*
|
17
24
|
Style/WordArray:
|
18
25
|
Exclude:
|
19
26
|
- spec/**/*
|
data/.travis.yml
CHANGED
@@ -1,11 +1,24 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
-
- 2.4.
|
4
|
-
- 2.4.
|
5
|
-
- 2.4.
|
6
|
-
- 2.4.3
|
3
|
+
- 2.4.4
|
4
|
+
- 2.4.5
|
5
|
+
- 2.4.6
|
7
6
|
- 2.5.0
|
8
7
|
- 2.5.1
|
8
|
+
- 2.5.2
|
9
|
+
- 2.5.3
|
10
|
+
- 2.5.4
|
11
|
+
- 2.5.5
|
12
|
+
- 2.6.0
|
13
|
+
- 2.6.1
|
14
|
+
- 2.6.2
|
15
|
+
- jruby-9.2.0.0
|
16
|
+
- jruby-9.2.1.0
|
17
|
+
- jruby-9.2.3.0
|
18
|
+
- jruby-9.2.4.0
|
19
|
+
- jruby-9.2.4.1
|
20
|
+
- jruby-9.2.5.0
|
21
|
+
- jruby-9.2.6.0
|
9
22
|
gemfile:
|
10
23
|
- Gemfile
|
11
24
|
branches:
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
## Version 0.0.2
|
2
|
+
|
3
|
+
* Add support for:
|
4
|
+
* rubies 2.4.4 - 2.6.2
|
5
|
+
* jrubyies 9.2.0.0 - 9.2.6.0
|
6
|
+
* Sort API consistency - when passing credentials use positional not keywork arguments, except:
|
7
|
+
* Initializing a new HTTP or Stomp client
|
8
|
+
* Initializing a new NetworkRail Schedule Fetcher
|
9
|
+
* Add National rail - Knowledge base - National service indicator via HTTP.
|
10
|
+
* Fix issue 1: OpenURI returns a StringIO not TempFile when size is under 10KB.
|
11
|
+
* Fix "undefined method `parse_cif_file'" when loading Network Rail schedule data.
|
12
|
+
|
1
13
|
## Version 0.0.1
|
2
14
|
|
3
15
|
* Initial release.
|
data/README.md
CHANGED
@@ -19,8 +19,12 @@ and Staging (which is what is currently being developed ready for moving to mast
|
|
19
19
|
## Ruby Versions
|
20
20
|
This gem supports the following versions of ruby, it may work on other versions but is not tested against them so don't rely on it.
|
21
21
|
|
22
|
-
*
|
23
|
-
|
22
|
+
* ruby:
|
23
|
+
* 2.4.4 - 2.4.6
|
24
|
+
* 2.5.0 - 2.5.5
|
25
|
+
* 2.6.0 - 2.6.2
|
26
|
+
* jruby:
|
27
|
+
* 9.2.0.0 - 9.2.6.0
|
24
28
|
|
25
29
|
|
26
30
|
## Rail Feeds
|
@@ -50,10 +54,10 @@ We follow the [Semantic Versioning](http://semver.org/) concept.
|
|
50
54
|
|
51
55
|
### Sources
|
52
56
|
|
53
|
-
| Source | Module | Module Alias | Support
|
54
|
-
| ------------- | ----------------------- | ------------ |
|
55
|
-
| Network Rail | RailFeeds::NetworkRail | NetRailFeeds | Being developed
|
56
|
-
| National Rail | RailFeeds::NationalRail | NatRailFeeds |
|
57
|
+
| Source | Module | Module Alias | Support |
|
58
|
+
| ------------- | ----------------------- | ------------ | --------------- |
|
59
|
+
| Network Rail | RailFeeds::NetworkRail | NetRailFeeds | Being developed |
|
60
|
+
| National Rail | RailFeeds::NationalRail | NatRailFeeds | |
|
57
61
|
|
58
62
|
### Feeds
|
59
63
|
|
@@ -72,6 +76,6 @@ We follow the [Semantic Versioning](http://semver.org/) concept.
|
|
72
76
|
| National Rail | stomp | Darwin Push Port | |
|
73
77
|
| National Rail | stomp | Darwin Timetable Feed | |
|
74
78
|
| National Rail | stomp | Knowledgebase | |
|
75
|
-
| National Rail | http | Knowledgebase |
|
79
|
+
| National Rail | http | Knowledgebase | Can download, fetch and parse NSI. |
|
76
80
|
| National Rail | soap | Darwin Webservice | |
|
77
81
|
| National Rail | rest | Historical Service Performance | |
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# National Rail - National Service Indicator
|
2
|
+
|
3
|
+
The national service indicator provides information on the current service
|
4
|
+
provided by each TOC.
|
5
|
+
|
6
|
+
```ruby
|
7
|
+
# Download the file and then get the data from it
|
8
|
+
RailFeeds::NationalRail::Credentials.configure(
|
9
|
+
username: 'YOUR USERNAME HERE',
|
10
|
+
password: 'YOUR PASSWORD HERE'
|
11
|
+
)
|
12
|
+
RailFeeds::NationalRail::KnowledgeBase::NationalServiceIndicator.download('file name')
|
13
|
+
data = RailFeeds::NationalRail::KnowledgeBase::NationalServiceIndicator.load_file('file name')
|
14
|
+
|
15
|
+
# Get data by fetching it from the web
|
16
|
+
RailFeeds::NationalRail::Credentials.configure(
|
17
|
+
username: 'YOUR USERNAME HERE',
|
18
|
+
password: 'YOUR PASSWORD HERE'
|
19
|
+
)
|
20
|
+
data = RailFeeds::NationalRail::KnowledgeBase::NationalServiceIndicator.fetch_data
|
21
|
+
```
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Network Rail CORPUS (Codes for Operations, Retail & Planning – a Unified Solution)
|
1
|
+
# Network Rail - CORPUS (Codes for Operations, Retail & Planning – a Unified Solution)
|
2
2
|
|
3
3
|
The CORPUS data is a list of indentification information for locations around the network.
|
4
4
|
See <https://wiki.openraildata.com/index.php/Reference_Data#CORPUS:_Location_Reference_Data>
|
@@ -16,13 +16,17 @@ You'll get an array of a data struct with the following attributes:
|
|
16
16
|
|
17
17
|
```ruby
|
18
18
|
# Download the CORPUS data and get the data from it
|
19
|
+
RailFeeds::NetworkRail::Credentials.configure(
|
20
|
+
username: 'YOUR USERNAME HERE',
|
21
|
+
password: 'YOUR PASSWORD HERE'
|
22
|
+
)
|
19
23
|
temp_file = RailFeeds::NetworkRail::CORPUS.fetch
|
20
|
-
data = RailFeeds::NetworkRail::CORPUS.load_file(temp_file
|
24
|
+
data = RailFeeds::NetworkRail::CORPUS.load_file(temp_file)
|
21
25
|
|
22
26
|
# Get data from a previously saved file
|
23
27
|
data = RailFeeds::NetworkRail::CORPUS.load_file('PATH TO FILE.json.gz')
|
24
28
|
|
25
|
-
# Get data from a previously saved and
|
29
|
+
# Get data from a previously saved and unzipped file
|
26
30
|
data = RailFeeds::NetworkRail::CORPUS.load_file('PATH TO FILE.json')
|
27
31
|
|
28
32
|
# Get data by fetching it from the web
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Network Rail SMART
|
1
|
+
# Network Rail - SMART
|
2
2
|
|
3
3
|
The SMART data is a periodically updated list of mappings between train describer berths
|
4
4
|
and locations, allowing for TD events to be translated into arrival/departure from location
|
@@ -18,8 +18,12 @@ reachable in each direction.
|
|
18
18
|
|
19
19
|
```ruby
|
20
20
|
# Download the SMART data and get the data from it
|
21
|
+
RailFeeds::NetworkRail::Credentials.configure(
|
22
|
+
username: 'YOUR USERNAME HERE',
|
23
|
+
password: 'YOUR PASSWORD HERE'
|
24
|
+
)
|
21
25
|
temp_file = RailFeeds::NetworkRail::SMART.fetch
|
22
|
-
step_data = RailFeeds::NetworkRail::SMART.load_file(temp_file
|
26
|
+
step_data = RailFeeds::NetworkRail::SMART.load_file(temp_file)
|
23
27
|
|
24
28
|
# Get the SMART data from a previously saved file
|
25
29
|
step_data = RailFeeds::NetworkRail::SMART.load_file('PATH TO FILE.json.gz')
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Network Rail Schedule
|
1
|
+
# Network Rail - Schedule
|
2
2
|
|
3
3
|
The schedule files from Network Rail contain:
|
4
4
|
|
@@ -36,14 +36,14 @@ RailFeeds::NetworkRail::Credentials.configure(
|
|
36
36
|
# 2. Fetch some files
|
37
37
|
fetcher = RailFeeds::NetworkRail::Schedule::Fetcher.new
|
38
38
|
|
39
|
-
fetcher.fetch_all_full(:cif) do |
|
39
|
+
fetcher.fetch_all_full(:cif) do |full_file_as_an_io|
|
40
40
|
...
|
41
41
|
end
|
42
42
|
|
43
|
-
fetcher.fetch_all_update('fri', :cif) do |
|
43
|
+
fetcher.fetch_all_update('fri', :cif) do |update_file_as_an_io|
|
44
44
|
...
|
45
45
|
end
|
46
|
-
# Each of the file variables will contain
|
46
|
+
# Each of the file variables will contain an IO object which can be used to read
|
47
47
|
# the CIF data (or passed to the parser to make use of). The files will be deleted
|
48
48
|
# at the end of the block.
|
49
49
|
```
|
@@ -34,6 +34,36 @@ module RailFeeds
|
|
34
34
|
@password = password.to_s.clone
|
35
35
|
end
|
36
36
|
|
37
|
+
# Get an array of [username, password].
|
38
|
+
# @return [Array<String>]
|
39
|
+
def to_a
|
40
|
+
[username, password]
|
41
|
+
end
|
42
|
+
|
43
|
+
# Get a hash of { username: ?, password: ? }.
|
44
|
+
# @return [Hash<Symbol => String>]
|
45
|
+
def to_h
|
46
|
+
{
|
47
|
+
username: username,
|
48
|
+
password: password
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
# Get an array of [username, password].
|
53
|
+
# @return [Array<String>]
|
54
|
+
def self.to_a
|
55
|
+
[username, password]
|
56
|
+
end
|
57
|
+
|
58
|
+
# Get a hash of { username: ?, password: ? }.
|
59
|
+
# @return [Hash<Symbol => String>]
|
60
|
+
def self.to_h
|
61
|
+
{
|
62
|
+
username: username,
|
63
|
+
password: password
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
37
67
|
def self.username
|
38
68
|
@username.clone
|
39
69
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailFeeds
|
4
|
+
# A wrapper class for ::Net::HTTP
|
5
|
+
class HTTPClient
|
6
|
+
include Logging
|
7
|
+
|
8
|
+
# Initialize a new http client.
|
9
|
+
# @param [RailFeeds::Credentials] credentials
|
10
|
+
# The credentials for connecting to the feed.
|
11
|
+
# @param [Logger] logger
|
12
|
+
# The logger for outputting evetns, if nil the global logger will be used.
|
13
|
+
def initialize(credentials: nil, logger: nil)
|
14
|
+
@credentials = credentials
|
15
|
+
self.logger = logger unless logger.nil?
|
16
|
+
end
|
17
|
+
|
18
|
+
# Fetch path from server.
|
19
|
+
# @param [String] url The URL to fetch.
|
20
|
+
# @yield contents
|
21
|
+
# @yieldparam [IO] file Either a Tempfile or StringIO.
|
22
|
+
def fetch(url, options = {})
|
23
|
+
logger.debug "fetching #{url.inspect}"
|
24
|
+
options[:http_basic_authentication] = @credentials.to_a
|
25
|
+
yield URI(url).open(options)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Fetch path from server and unzip it.
|
29
|
+
# @param [String] url The URL to fetch. For child classes this is just the path.
|
30
|
+
# @yield contents
|
31
|
+
# @yieldparam [Zlib::GzipReader] reader The unzippable content of the file.
|
32
|
+
def fetch_unzipped(url)
|
33
|
+
logger.debug "get_unzipped(#{url.inspect})"
|
34
|
+
fetch(url) do |gz_file|
|
35
|
+
reader = Zlib::GzipReader.new gz_file
|
36
|
+
yield reader
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Download path from server.
|
41
|
+
# @param [String] url The URL to download. For child classes this is just the path.
|
42
|
+
# @param [String] file The path to the file to save the contents in.
|
43
|
+
def download(url, file)
|
44
|
+
logger.debug "download(#{url.inspect}, #{file.inspect})"
|
45
|
+
fetch(url) do |src|
|
46
|
+
File.open(file, 'w') do |dst|
|
47
|
+
IO.copy_stream src, dst
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
attr_reader :credentials
|
55
|
+
end
|
56
|
+
end
|
data/lib/rail_feeds/logging.rb
CHANGED
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailFeeds
|
4
|
+
module NationalRail
|
5
|
+
# A Class to store username & password required to access national rail feeds
|
6
|
+
# Can be used to set a global default but create new instances with
|
7
|
+
# specific ones for a specific use.
|
8
|
+
class Credentials < RailFeeds::Credentials
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailFeeds
|
4
|
+
module NationalRail
|
5
|
+
# A wrapper class for ::Net::HTTP
|
6
|
+
class HTTPClient < RailFeeds::HTTPClient
|
7
|
+
def initialize(credentials: nil, **args)
|
8
|
+
credentials ||= RailFeeds::NationalRail::Credentials
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
# Fetch path from server.
|
13
|
+
# @param [String] path The path to fetch.
|
14
|
+
# @yield contents
|
15
|
+
# @yieldparam [IO] file Either a Tempfile or StringIO.
|
16
|
+
def fetch(path)
|
17
|
+
super "https://datafeeds.nationalrail.co.uk/#{path}", 'X-Auth-Token' => auth_token
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
# rubocop:disable Metrics/AbcSize
|
23
|
+
def auth_token
|
24
|
+
return @auth_token if !@auth_token.nil? && @auth_token_expires_at >= Time.now
|
25
|
+
|
26
|
+
logger.info 'Getting an auth token for national rail.'
|
27
|
+
response = Net::HTTP.post_form(
|
28
|
+
URI('https://datafeeds.nationalrail.co.uk/authenticate'),
|
29
|
+
credentials.to_h
|
30
|
+
)
|
31
|
+
response.value # Raise an exception if not successful
|
32
|
+
data = JSON.parse(response.body)
|
33
|
+
logger.debug "Got auth token data: #{data.inspect}"
|
34
|
+
token = data.fetch('token')
|
35
|
+
|
36
|
+
# Token expires in 1 hour. Using 55 minutes provides a safety margin.
|
37
|
+
@auth_token_expires_at = Time.now + (55 * 60)
|
38
|
+
logger.debug "Auth token expires at #{@auth_token_expires_at}."
|
39
|
+
|
40
|
+
@auth_token = token
|
41
|
+
end
|
42
|
+
# rubocop:enable Metrics/AbcSize
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailFeeds
|
4
|
+
module NationalRail
|
5
|
+
module KnowledgeBase
|
6
|
+
# A module for accessing the national service indicator
|
7
|
+
# from the national rail knowledge base.
|
8
|
+
module NationalServiceIndicator
|
9
|
+
TOC = Struct.new(
|
10
|
+
:code, :name, :status, :twitter_account, :additional_info, :service_groups
|
11
|
+
) do
|
12
|
+
def to_s
|
13
|
+
"#{code} - #{name}\n" \
|
14
|
+
"#{status}\n#{service_groups.join("\n")}\n" \
|
15
|
+
"@#{twitter_account} - #{additional_info}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
Status = Struct.new(:title, :description, :image) do
|
20
|
+
def to_s
|
21
|
+
"#{title} - #{description} - #{image}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
ServiceGroup = Struct.new(:disruption_id, :name, :detail, :url) do
|
26
|
+
def to_s
|
27
|
+
"#{name} - #{detail}\n#{disruption_id} #{url}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Download the current data.
|
32
|
+
# @param [RailFeeds::NationalRail::Credentials] credentials
|
33
|
+
# @param [String] file
|
34
|
+
# The path to the file to save the .xml download in.
|
35
|
+
def self.download(file, credentials = Credentials)
|
36
|
+
client = HTTPClient.new(credentials: credentials)
|
37
|
+
client.download 'darwin/api/staticfeeds/4.0/serviceIndicators', file
|
38
|
+
end
|
39
|
+
|
40
|
+
# Fetch the current data.
|
41
|
+
# @param [RailFeeds::NationalRail::Credentials] credentials
|
42
|
+
# @return [IO]
|
43
|
+
def self.fetch(credentials = Credentials, &block)
|
44
|
+
client = HTTPClient.new(credentials: credentials)
|
45
|
+
client.fetch 'darwin/api/staticfeeds/4.0/serviceIndicators', &block
|
46
|
+
end
|
47
|
+
|
48
|
+
# Load data from either a .json or .json.gz file.
|
49
|
+
# @param [String] file The path of the file to open.
|
50
|
+
# @return
|
51
|
+
# [Array<RailFeeds::NationalRail::KnowledgeBase::NationalServiceIndicator::TOC>]
|
52
|
+
def self.load_file(file)
|
53
|
+
parse_xml File.read(file)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Load data from the internet.
|
57
|
+
# @param [RailFeeds::NationalRail::Credentials] credentials
|
58
|
+
# The credentials to authenticate with.
|
59
|
+
# @return
|
60
|
+
# [Array<RailFeeds::NationalRail::KnowledgeBase::NationalServiceIndicator::TOC>]
|
61
|
+
def self.fetch_data(credentials = Credentials)
|
62
|
+
fetch(credentials: credentials) do |file|
|
63
|
+
parse_xml file.read
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# rubocop:disable Metrics/AbcSize
|
68
|
+
# rubocop:disable Metrics/MethodLength
|
69
|
+
def self.parse_xml(xml)
|
70
|
+
options = Nokogiri::XML::ParseOptions.new.nonet.noent.noblanks
|
71
|
+
doc = Nokogiri::XML.parse(xml, nil, nil, options)
|
72
|
+
doc.xpath('/xmlns:NSI/xmlns:TOC').map do |toc_node|
|
73
|
+
TOC.new(
|
74
|
+
toc_node.xpath('./xmlns:TocCode').first&.content,
|
75
|
+
toc_node.xpath('./xmlns:TocName').first&.content,
|
76
|
+
Status.new(
|
77
|
+
toc_node.xpath('./xmlns:Status').first&.content,
|
78
|
+
toc_node.xpath('./xmlns:StatusDescription').first&.content,
|
79
|
+
toc_node.xpath('./xmlns:StatusImage').first&.content
|
80
|
+
),
|
81
|
+
toc_node.xpath('./xmlns:TwitterAccount').first&.content,
|
82
|
+
toc_node.xpath('./xmlns:AdditionalInfo').first&.content,
|
83
|
+
toc_node.xpath('./xmlns:ServiceGroup').map do |service_group|
|
84
|
+
ServiceGroup.new(
|
85
|
+
service_group.xpath('./xmlns:CurrentDisruption').first&.content,
|
86
|
+
service_group.xpath('./xmlns:GroupName').first&.content,
|
87
|
+
service_group.xpath('./xmlns:CustomDetail').first&.content,
|
88
|
+
service_group.xpath('./xmlns:CustomURL').first&.content
|
89
|
+
)
|
90
|
+
end
|
91
|
+
)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
# rubocop:enable Metrics/AbcSize
|
95
|
+
# rubocop:enable Metrics/MethodLength
|
96
|
+
private_class_method :parse_xml
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'json'
|
4
|
-
|
5
3
|
module RailFeeds
|
6
4
|
module NetworkRail
|
7
5
|
# A module for getting information out of the CORPUS data.
|
@@ -14,15 +12,15 @@ module RailFeeds
|
|
14
12
|
# @param [RailFeeds::NetworkRail::Credentials] credentials
|
15
13
|
# @param [String] file
|
16
14
|
# The path to the file to save the .json.gz download in.
|
17
|
-
def self.download(file, credentials
|
15
|
+
def self.download(file, credentials = Credentials)
|
18
16
|
client = HTTPClient.new(credentials: credentials)
|
19
17
|
client.download 'ntrod/SupportingFileAuthenticate?type=CORPUS', file
|
20
18
|
end
|
21
19
|
|
22
20
|
# Fetch the current CORPUS data.
|
23
21
|
# @param [RailFeeds::NetworkRail::Credentials] credentials
|
24
|
-
# @return [
|
25
|
-
def self.fetch(credentials
|
22
|
+
# @return [IO]
|
23
|
+
def self.fetch(credentials = Credentials)
|
26
24
|
client = HTTPClient.new(credentials: credentials)
|
27
25
|
client.fetch 'ntrod/SupportingFileAuthenticate?type=CORPUS'
|
28
26
|
end
|
@@ -42,7 +40,7 @@ module RailFeeds
|
|
42
40
|
# @param [RailFeeds::NetworkRail::Credentials] credentials
|
43
41
|
# The credentials to authenticate with.
|
44
42
|
# @return [Array<RailFeeds::NetworkRail::CORPUS::Data>]
|
45
|
-
def self.fetch_data(credentials
|
43
|
+
def self.fetch_data(credentials = Credentials)
|
46
44
|
client = HTTPClient.new(credentials: credentials)
|
47
45
|
client.fetch_unzipped('ntrod/SupportingFileAuthenticate?type=CORPUS') do |file|
|
48
46
|
break parse_json file.read
|
@@ -69,6 +67,7 @@ module RailFeeds
|
|
69
67
|
|
70
68
|
def self.nilify(item)
|
71
69
|
return nil if item.nil? || item.empty?
|
70
|
+
|
72
71
|
item
|
73
72
|
end
|
74
73
|
private_class_method :nilify
|
@@ -6,17 +6,6 @@ module RailFeeds
|
|
6
6
|
# Can be used to set a global default but create new instances with
|
7
7
|
# specific ones for a specific use.
|
8
8
|
class Credentials < RailFeeds::Credentials
|
9
|
-
# Get an array of [username, password].
|
10
|
-
# @return [Array<String>]
|
11
|
-
def to_a
|
12
|
-
[username, password]
|
13
|
-
end
|
14
|
-
|
15
|
-
# Get an array of [username, password].
|
16
|
-
# @return [Array<String>]
|
17
|
-
def self.to_a
|
18
|
-
[username, password]
|
19
|
-
end
|
20
9
|
end
|
21
10
|
end
|
22
11
|
end
|
@@ -1,56 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'open-uri'
|
4
|
-
|
5
3
|
module RailFeeds
|
6
4
|
module NetworkRail
|
7
5
|
# A wrapper class for ::Net::HTTP
|
8
|
-
class HTTPClient
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
# Initialize a new http client.
|
14
|
-
# @param [RailFeeds::NetworkRail::Credentials] credentials
|
15
|
-
# The credentials for connecting to the feed.
|
16
|
-
# @param [Logger] logger
|
17
|
-
# The logger for outputting evetns, if nil the global logger will be used.
|
18
|
-
def initialize(credentials: Credentials, logger: nil)
|
19
|
-
@credentials = credentials
|
20
|
-
self.logger = logger unless logger.nil?
|
6
|
+
class HTTPClient < RailFeeds::HTTPClient
|
7
|
+
def initialize(credentials: nil, **args)
|
8
|
+
credentials ||= RailFeeds::NetworkRail::Credentials
|
9
|
+
super
|
21
10
|
end
|
22
11
|
|
23
|
-
# Fetch path from
|
12
|
+
# Fetch path from server.
|
24
13
|
# @param [String] path The path to fetch.
|
25
|
-
# @yield
|
26
|
-
# @yieldparam [
|
14
|
+
# @yield contents
|
15
|
+
# @yieldparam [IO] file Either a Tempfile or StringIO.
|
27
16
|
def fetch(path)
|
28
|
-
|
29
|
-
uri = URI("https://#{HOST}/#{path}")
|
30
|
-
yield uri.open(http_basic_authentication: @credentials.to_a)
|
31
|
-
end
|
32
|
-
|
33
|
-
# Fetch path from network rail server and unzip it.
|
34
|
-
# @param [String] path The path to fetch.
|
35
|
-
# @yield [reader] Once the block has run the temp file will be deleted.
|
36
|
-
# @yieldparam [Zlib::GzipReader] reader The unzippable content of the file.
|
37
|
-
def fetch_unzipped(path)
|
38
|
-
logger.debug "get_unzipped(#{path.inspect})"
|
39
|
-
fetch(path) do |gz_file|
|
40
|
-
yield Zlib::GzipReader.open(gz_file.path)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
# Download path from netwrok rail server.
|
45
|
-
# @param [String] path The path to download.
|
46
|
-
# @param [String] file The path to the file to save the contents in.
|
47
|
-
def download(path, file)
|
48
|
-
logger.debug "download(#{path.inspect}, #{file.inspect})"
|
49
|
-
fetch(path) do |src|
|
50
|
-
File.open(file, 'w') do |dst|
|
51
|
-
IO.copy_stream src, dst
|
52
|
-
end
|
53
|
-
end
|
17
|
+
super "https://datafeeds.networkrail.co.uk/#{path}"
|
54
18
|
end
|
55
19
|
end
|
56
20
|
end
|
@@ -181,7 +181,7 @@ module RailFeeds
|
|
181
181
|
# rubocop:enable Metrics/AbcSize
|
182
182
|
|
183
183
|
# rubocop:disable Metrics/MethodLength
|
184
|
-
def to_json
|
184
|
+
def to_json(**opts)
|
185
185
|
{
|
186
186
|
'JsonAssociationV1' => {
|
187
187
|
'transaction_type' => 'Create',
|
@@ -198,7 +198,7 @@ module RailFeeds
|
|
198
198
|
'diagram_type' => 'T',
|
199
199
|
'CIF_stp_indicator' => stp_indicator_to_cif
|
200
200
|
}
|
201
|
-
}.to_json
|
201
|
+
}.to_json(**opts)
|
202
202
|
end
|
203
203
|
# rubocop:enable Metrics/MethodLength
|
204
204
|
end
|
@@ -52,7 +52,7 @@ module RailFeeds
|
|
52
52
|
# @param [IO] file
|
53
53
|
# The file to load data from.
|
54
54
|
def load_cif_file(file)
|
55
|
-
@parser.
|
55
|
+
@parser.parse_file file
|
56
56
|
|
57
57
|
logger.info "Currently have #{associations.count} associations, " \
|
58
58
|
"#{tiplocs.count} tiplocs, #{trains.count} trains."
|
@@ -92,7 +92,7 @@ module RailFeeds
|
|
92
92
|
# The credentials for connecting to the feed.
|
93
93
|
# @return [RailFeeds::NetworkRail::Schedule::Header::CIF]
|
94
94
|
# The header of the last file added.
|
95
|
-
def fetch_data(credentials
|
95
|
+
def fetch_data(credentials = Credentials)
|
96
96
|
fetcher = Fetcher.new credentials: credentials
|
97
97
|
|
98
98
|
method = if last_header.nil? ||
|
@@ -198,6 +198,7 @@ module RailFeeds
|
|
198
198
|
trains[train_schedule.uid] ||= []
|
199
199
|
index = trains[train_schedule.uid].index train_schedule
|
200
200
|
return do_train_schedule_create(parser, train_schedule) if index.nil?
|
201
|
+
|
201
202
|
trains[train_schedule.uid][index] = train_schedule
|
202
203
|
end
|
203
204
|
|