rail_feeds 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/.rspec +3 -0
- data/.rubocop.yml +31 -0
- data/.travis.yml +26 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +6 -0
- data/Guardfile +25 -0
- data/LICENSE.md +32 -0
- data/README.md +77 -0
- data/Rakefile +3 -0
- data/doc/guides/Logging.md +13 -0
- data/doc/guides/Network Rail/CORPUS.md +34 -0
- data/doc/guides/Network Rail/SMART.md +39 -0
- data/doc/guides/Network Rail/Schedule.md +138 -0
- data/file +0 -0
- data/lib/rail_feeds/credentials.rb +45 -0
- data/lib/rail_feeds/logging.rb +51 -0
- data/lib/rail_feeds/network_rail/corpus.rb +77 -0
- data/lib/rail_feeds/network_rail/credentials.rb +22 -0
- data/lib/rail_feeds/network_rail/http_client.rb +57 -0
- data/lib/rail_feeds/network_rail/schedule/association.rb +208 -0
- data/lib/rail_feeds/network_rail/schedule/data.rb +215 -0
- data/lib/rail_feeds/network_rail/schedule/days.rb +95 -0
- data/lib/rail_feeds/network_rail/schedule/fetcher.rb +193 -0
- data/lib/rail_feeds/network_rail/schedule/header/cif.rb +102 -0
- data/lib/rail_feeds/network_rail/schedule/header/json.rb +79 -0
- data/lib/rail_feeds/network_rail/schedule/header.rb +22 -0
- data/lib/rail_feeds/network_rail/schedule/parser/cif.rb +141 -0
- data/lib/rail_feeds/network_rail/schedule/parser/json.rb +87 -0
- data/lib/rail_feeds/network_rail/schedule/parser.rb +108 -0
- data/lib/rail_feeds/network_rail/schedule/stp_indicator.rb +72 -0
- data/lib/rail_feeds/network_rail/schedule/tiploc.rb +100 -0
- data/lib/rail_feeds/network_rail/schedule/train_schedule/change_en_route.rb +158 -0
- data/lib/rail_feeds/network_rail/schedule/train_schedule/location/intermediate.rb +119 -0
- data/lib/rail_feeds/network_rail/schedule/train_schedule/location/origin.rb +91 -0
- data/lib/rail_feeds/network_rail/schedule/train_schedule/location/terminating.rb +72 -0
- data/lib/rail_feeds/network_rail/schedule/train_schedule/location.rb +76 -0
- data/lib/rail_feeds/network_rail/schedule/train_schedule.rb +392 -0
- data/lib/rail_feeds/network_rail/schedule.rb +33 -0
- data/lib/rail_feeds/network_rail/smart.rb +186 -0
- data/lib/rail_feeds/network_rail/stomp_client.rb +77 -0
- data/lib/rail_feeds/network_rail.rb +16 -0
- data/lib/rail_feeds/version.rb +14 -0
- data/lib/rail_feeds.rb +10 -0
- data/rail_feeds.gemspec +32 -0
- data/spec/fixtures/network_rail/schedule/data/full.yaml +60 -0
- data/spec/fixtures/network_rail/schedule/data/starting.yaml +131 -0
- data/spec/fixtures/network_rail/schedule/data/update-gap.yaml +10 -0
- data/spec/fixtures/network_rail/schedule/data/update-next.yaml +13 -0
- data/spec/fixtures/network_rail/schedule/data/update-old.yaml +10 -0
- data/spec/fixtures/network_rail/schedule/data/update.yaml +112 -0
- data/spec/fixtures/network_rail/schedule/parser/train_create.json +1 -0
- data/spec/fixtures/network_rail/schedule/parser/train_delete.json +1 -0
- data/spec/fixtures/network_rail/schedule/train_schedule/json-data.yaml +67 -0
- data/spec/rail_feeds/credentials_spec.rb +46 -0
- data/spec/rail_feeds/logging_spec.rb +81 -0
- data/spec/rail_feeds/network_rail/corpus_spec.rb +92 -0
- data/spec/rail_feeds/network_rail/credentials_spec.rb +22 -0
- data/spec/rail_feeds/network_rail/http_client_spec.rb +88 -0
- data/spec/rail_feeds/network_rail/schedule/association_spec.rb +205 -0
- data/spec/rail_feeds/network_rail/schedule/data_spec.rb +219 -0
- data/spec/rail_feeds/network_rail/schedule/days_shared.rb +99 -0
- data/spec/rail_feeds/network_rail/schedule/days_spec.rb +4 -0
- data/spec/rail_feeds/network_rail/schedule/fetcher_spec.rb +228 -0
- data/spec/rail_feeds/network_rail/schedule/header/cif_spec.rb +72 -0
- data/spec/rail_feeds/network_rail/schedule/header/json_spec.rb +51 -0
- data/spec/rail_feeds/network_rail/schedule/header_spec.rb +19 -0
- data/spec/rail_feeds/network_rail/schedule/parser/cif_spec.rb +197 -0
- data/spec/rail_feeds/network_rail/schedule/parser/json_spec.rb +172 -0
- data/spec/rail_feeds/network_rail/schedule/parser_spec.rb +34 -0
- data/spec/rail_feeds/network_rail/schedule/stp_indicator_shared.rb +49 -0
- data/spec/rail_feeds/network_rail/schedule/stp_indicator_spec.rb +4 -0
- data/spec/rail_feeds/network_rail/schedule/tiploc_spec.rb +77 -0
- data/spec/rail_feeds/network_rail/schedule/train_schedule/change_en_route_spec.rb +121 -0
- data/spec/rail_feeds/network_rail/schedule/train_schedule/location/intermediate_spec.rb +95 -0
- data/spec/rail_feeds/network_rail/schedule/train_schedule/location/origin_spec.rb +87 -0
- data/spec/rail_feeds/network_rail/schedule/train_schedule/location/terminating_spec.rb +81 -0
- data/spec/rail_feeds/network_rail/schedule/train_schedule/location_spec.rb +35 -0
- data/spec/rail_feeds/network_rail/schedule/train_schedule_spec.rb +284 -0
- data/spec/rail_feeds/network_rail/schedule_spec.rb +41 -0
- data/spec/rail_feeds/network_rail/smart_spec.rb +194 -0
- data/spec/rail_feeds/network_rail/stomp_client_spec.rb +151 -0
- data/spec/rail_feeds/network_rail_spec.rb +7 -0
- data/spec/rail_feeds_spec.rb +11 -0
- data/spec/spec_helper.rb +47 -0
- metadata +282 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bd597c45ef2dc68d4da4278cfeda76ad9ae61e128309071a89c85adb27b510e4
|
4
|
+
data.tar.gz: 4af4ee4fb4302f304b444e87804ab6d3813098ccf637fe957b57ac9cbbbeb8f3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 23f62dfd13351944c0c24e204e5c9788a53a4871d03440a5dfae3a121769044c198bc41b7330b3f54a83bb82a4488218b4958b2575797d9d0a637729fef32268
|
7
|
+
data.tar.gz: b3e18f1f140f3e16c6c2ad67358cd2269dc4ed43a450384347fed1c73d208353cd13029f2b1c330725f87880be7494e894d2f451baf30a39c806aef9199501a7
|
data/.gitignore
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Because this is a gem, ignore Gemfile.lock:
|
2
|
+
|
3
|
+
Gemfile.lock
|
4
|
+
|
5
|
+
# And because this is Ruby, ignore the following
|
6
|
+
# (source: https://github.com/github/gitignore/blob/master/Ruby.gitignore):
|
7
|
+
|
8
|
+
notes.txt
|
9
|
+
todo.txt
|
10
|
+
*.gem
|
11
|
+
*.rbc
|
12
|
+
.bundle
|
13
|
+
.config
|
14
|
+
coverage
|
15
|
+
InstalledFiles
|
16
|
+
lib/bundler/man
|
17
|
+
pkg
|
18
|
+
rdoc
|
19
|
+
spec/reports
|
20
|
+
test/tmp
|
21
|
+
test/version_tmp
|
22
|
+
tmp
|
23
|
+
gemfiles/*.lock
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.3
|
3
|
+
Style/SignalException:
|
4
|
+
Enabled: false
|
5
|
+
Metrics/MethodLength:
|
6
|
+
Max: 15
|
7
|
+
Metrics/AbcSize:
|
8
|
+
Max: 17.5
|
9
|
+
Metrics/LineLength:
|
10
|
+
Max: 90
|
11
|
+
Exclude:
|
12
|
+
- rail_feeds.gemspec
|
13
|
+
- spec/**/*
|
14
|
+
Layout/TrailingBlankLines:
|
15
|
+
Exclude:
|
16
|
+
- rail_feeds.gemspec
|
17
|
+
Style/WordArray:
|
18
|
+
Exclude:
|
19
|
+
- spec/**/*
|
20
|
+
Layout/EmptyLines:
|
21
|
+
Exclude:
|
22
|
+
- spec/**/*
|
23
|
+
Metrics/BlockLength:
|
24
|
+
Exclude:
|
25
|
+
- spec/**/*
|
26
|
+
Style/NumericLiterals:
|
27
|
+
Exclude:
|
28
|
+
- spec/**/*
|
29
|
+
Security/YAMLLoad:
|
30
|
+
Exclude:
|
31
|
+
- spec/**/*
|
data/.travis.yml
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.4.0
|
4
|
+
- 2.4.1
|
5
|
+
- 2.4.2
|
6
|
+
- 2.4.3
|
7
|
+
- 2.5.0
|
8
|
+
- 2.5.1
|
9
|
+
gemfile:
|
10
|
+
- Gemfile
|
11
|
+
branches:
|
12
|
+
only:
|
13
|
+
- master
|
14
|
+
- staging
|
15
|
+
- /gh(?:\d)+(?:-.+)?/
|
16
|
+
- /dev_ver_\d+\.\d+/
|
17
|
+
before_install: gem update bundler
|
18
|
+
script:
|
19
|
+
- bundle exec rubocop
|
20
|
+
- bundle exec rspec
|
21
|
+
notifications:
|
22
|
+
slack:
|
23
|
+
on_success: always
|
24
|
+
on_failure: always
|
25
|
+
rooms:
|
26
|
+
- secure: CH9idL8/an98uf8uvZ0Pzp7LN9ejdFXh40L6obz5x3tViTzvqo2pqNdryom1E6Dw3NJ7nh4h91XxAq6IZLzrwhSGVGri4tA6EPls6NnkN/UvaK/oCt71ZUaC07hb7SSrc+sQN2CRXMFzxkRBvQ8EKlq+F+Qtj28h0Rebfd79CE+i2NYuAtimYRezOmyLKYUHKRkhYtXbR12FKkNW+2pNNx/Aq02bP/sMXTVdk3k+1bsnpjOoan0m7c2SUkYRD9vmY4u9vxTt2lFFJ+V5NWntXb3y5ttctR9EukULHS2mqFA4q+i6OAJaJUIGWCeWTsB1V3fPuICcZHPV1gF4wVAfV/xees1STJuzGRBpIRTUPd/iXfnNT35e5o97quSHolYx0nCRstonW8IOwlegDqJCbmu8nAaP2M42VkZ4u0Qi1MgzFZ3XcmlLsIrypQHbLnQZKgcnBPxY/8AuqDY9JgiY9RaTMT5xyPox33yAC41MaNYouicyfFSZ4Q+4QFNaPtjaG+N5VR7neMGa5uCXGFHR8H5pWDV5oUFlZzep3bMnrkT9nb/56UjZlAF94nYPEs0nsEm+r35b/g/WWGB+t8UpHzl/jK0s74NbASu+MyNN6X+FiaxOB3WvaFz0wJNqN46SINJjHk1CDhquD1qoyLI+R6AtrRkFvlgaXf6RCSfsWCo=
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
guard(
|
4
|
+
'rspec',
|
5
|
+
all_on_start: true,
|
6
|
+
all_after_pass: true,
|
7
|
+
cmd: 'bundle exec rspec'
|
8
|
+
) do
|
9
|
+
watch(%r{^spec/.+_spec\.rb$})
|
10
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
11
|
+
watch('spec/spec_helper.rb') { 'spec' }
|
12
|
+
watch(%r{^spec/.+_shared\.rb$}) { 'spec' }
|
13
|
+
end
|
14
|
+
|
15
|
+
guard(
|
16
|
+
'rubocop',
|
17
|
+
all_on_start: true,
|
18
|
+
all_after_pass: true,
|
19
|
+
notification: true,
|
20
|
+
cmd: 'bundle exec rubocop'
|
21
|
+
) do
|
22
|
+
watch(%r{^lib/(.+)\.rb$})
|
23
|
+
watch(%r{^spec/.+_spec\.rb$})
|
24
|
+
watch('.rubocop.yml')
|
25
|
+
end
|
data/LICENSE.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
##Copyright
|
2
|
+
Copyright (c) 2018, Robert Gauld. All rights reserved.
|
3
|
+
|
4
|
+
|
5
|
+
##License
|
6
|
+
This code can be used under the BSD License (reproduced below).
|
7
|
+
Commiters to the project give Robert Gauld the right to redistribute their commits
|
8
|
+
under the BSD license.
|
9
|
+
|
10
|
+
|
11
|
+
###BSD License
|
12
|
+
Redistribution and use in source and binary forms, with or without modification,
|
13
|
+
are permitted provided that the following conditions are met:
|
14
|
+
|
15
|
+
- Redistributions of source code must retain the above copyright notice,
|
16
|
+
this list of conditions and the following disclaimer.
|
17
|
+
- Redistributions in binary form must reproduce the above copyright notice,
|
18
|
+
this list of conditions and the following disclaimer in the documentation and/or
|
19
|
+
other materials provided with the distribution.
|
20
|
+
- Neither the name of the project nor the names of its contributors
|
21
|
+
may be used to endorse or promote products derived from this software
|
22
|
+
without specific prior written permission.
|
23
|
+
|
24
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
25
|
+
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
26
|
+
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
27
|
+
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
28
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
29
|
+
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
30
|
+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
31
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
32
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
[![Gem Version](https://badge.fury.io/rb/rail_feeds.png)](http://badge.fury.io/rb/rail_feeds)
|
2
|
+
|
3
|
+
Master branch:
|
4
|
+
[![Build Status](https://secure.travis-ci.org/robertgauld/rail_feeds.png?branch=master)](http://travis-ci.org/robertgauld/rail_feeds)
|
5
|
+
[![Coveralls Status](https://coveralls.io/repos/robertgauld/rail_feeds/badge.png?branch=master)](https://coveralls.io/r/robertgauld/rail_feeds)
|
6
|
+
[![Code Climate](https://codeclimate.com/github/robertgauld/rail_feeds.png?branch=master)](https://codeclimate.com/github/robertgauld/rail_feeds)
|
7
|
+
|
8
|
+
Staging branch:
|
9
|
+
[![Build Status](https://secure.travis-ci.org/robertgauld/rail_feeds.png?branch=staging)](http://travis-ci.org/robertgauld/rail_feeds)
|
10
|
+
[![Coveralls Status](https://coveralls.io/repos/robertgauld/rail_feeds/badge.png?branch=staging)](https://coveralls.io/r/robertgauld/rail_feeds)
|
11
|
+
|
12
|
+
|
13
|
+
## Build State
|
14
|
+
This project uses continuous integration to help ensure that a quality product is delivered.
|
15
|
+
Travis CI monitors two branches (versions) of the code - Master (which is what gets released)
|
16
|
+
and Staging (which is what is currently being developed ready for moving to master).
|
17
|
+
|
18
|
+
|
19
|
+
## Ruby Versions
|
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
|
+
|
22
|
+
* 2.4.0 - 2.4.3
|
23
|
+
* 2.5.0 - 2.5.1
|
24
|
+
|
25
|
+
|
26
|
+
## Rail Feeds
|
27
|
+
|
28
|
+
Make use of the various open data rails feeds in the UK.
|
29
|
+
For more details of what feeds are available visit [The Open Rail Data Wiki](https://wiki.openraildata.com).
|
30
|
+
|
31
|
+
## Installation
|
32
|
+
|
33
|
+
Add to your Gemfile and run the `bundle` command to install it.
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
gem 'rail_feeds', '~> 0.1'
|
37
|
+
```
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
## Documentation & Versioning
|
42
|
+
|
43
|
+
Documentation can be found on [rubydoc.info](http://rubydoc.info/github/robertgauld/rail_feeds/master/frames)
|
44
|
+
Some guides can be found in the [doc folder of the repo](https://github.com/robertgauld/rail_feeds/tree/master/doc/guides).
|
45
|
+
|
46
|
+
We follow the [Semantic Versioning](http://semver.org/) concept.
|
47
|
+
|
48
|
+
|
49
|
+
## Feed Support
|
50
|
+
|
51
|
+
### Sources
|
52
|
+
|
53
|
+
| Source | Module | Module Alias | Support |
|
54
|
+
| ------------- | ----------------------- | ------------ | -------------------------- |
|
55
|
+
| Network Rail | RailFeeds::NetworkRail | NetRailFeeds | Being developed |
|
56
|
+
| National Rail | RailFeeds::NationalRail | NatRailFeeds | None yet - any volunteers? |
|
57
|
+
|
58
|
+
### Feeds
|
59
|
+
|
60
|
+
| Source | Client | Feed | Status |
|
61
|
+
| ------------- | ------ | ------------------------------------ | ------------------------------------ |
|
62
|
+
| Network Rail | stomp | Real Time Public Performance Measure | Todo |
|
63
|
+
| Network Rail | stomp | Temporary Speed Restriction | Todo |
|
64
|
+
| Network Rail | stomp | Train Describer | Todo |
|
65
|
+
| Network Rail | stomp | Train Movements | Todo |
|
66
|
+
| Network Rail | stomp | Very Short Term Planning | Todo |
|
67
|
+
| Network Rail | http | Schedule | Can download, fetch, parse and dump. |
|
68
|
+
| Network Rail | http | CORPUS (location data) | Can download, fetch and parse. |
|
69
|
+
| Network Rail | http | SMART (berth stepping data) | Can download, fetch and parse. |
|
70
|
+
| Network Rail | http | Train Planning Data | Todo |
|
71
|
+
| Network Rail | http | Train Planning Network Model | Todo |
|
72
|
+
| National Rail | stomp | Darwin Push Port | |
|
73
|
+
| National Rail | stomp | Darwin Timetable Feed | |
|
74
|
+
| National Rail | stomp | Knowledgebase | |
|
75
|
+
| National Rail | http | Knowledgebase | |
|
76
|
+
| National Rail | soap | Darwin Webservice | |
|
77
|
+
| National Rail | rest | Historical Service Performance | |
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Logging
|
2
|
+
|
3
|
+
By default events are logged to STDOUT.
|
4
|
+
|
5
|
+
To replace the logger in use:
|
6
|
+
``` ruby
|
7
|
+
RailFeeds::Logging.logger = YOUR NEW LOGGER HERE
|
8
|
+
```
|
9
|
+
|
10
|
+
To access the logger in use, for example to change the log level:
|
11
|
+
``` ruby
|
12
|
+
RailFeeds::Logging.logger ...
|
13
|
+
```
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Network Rail CORPUS (Codes for Operations, Retail & Planning – a Unified Solution)
|
2
|
+
|
3
|
+
The CORPUS data is a list of indentification information for locations around the network.
|
4
|
+
See <https://wiki.openraildata.com/index.php/Reference_Data#CORPUS:_Location_Reference_Data>
|
5
|
+
for many more details.
|
6
|
+
|
7
|
+
You'll get an array of a data struct with the following attributes:
|
8
|
+
|
9
|
+
* tiploc - TIPLOC code (e.g. "ERGNCHP")
|
10
|
+
* stanox - STANOX code (e.g. 78370)
|
11
|
+
* crs - 3 letter location code (e.g. "ECP")
|
12
|
+
* uic - UIC code (e.g. 3750)
|
13
|
+
* nlc - NLC code (e.g. "37500")
|
14
|
+
* nlc_description - Description of the NLC (e.g. "ENERGLYN & CHURCHILL PARK")
|
15
|
+
* nlc_short_description - 16 character version (e.g. "ENERGLYN & C PK")
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
# Download the CORPUS data and get the data from it
|
19
|
+
temp_file = RailFeeds::NetworkRail::CORPUS.fetch
|
20
|
+
data = RailFeeds::NetworkRail::CORPUS.load_file(temp_file.path)
|
21
|
+
|
22
|
+
# Get data from a previously saved file
|
23
|
+
data = RailFeeds::NetworkRail::CORPUS.load_file('PATH TO FILE.json.gz')
|
24
|
+
|
25
|
+
# Get data from a previously saved and extracted file
|
26
|
+
data = RailFeeds::NetworkRail::CORPUS.load_file('PATH TO FILE.json')
|
27
|
+
|
28
|
+
# Get data by fetching it from the web
|
29
|
+
RailFeeds::NetworkRail::Credentials.configure(
|
30
|
+
username: 'YOUR USERNAME HERE',
|
31
|
+
password: 'YOUR PASSWORD HERE'
|
32
|
+
)
|
33
|
+
data = RailFeeds::NetworkRail::CORPUS.fetch_data
|
34
|
+
```
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# Network Rail SMART
|
2
|
+
|
3
|
+
The SMART data is a periodically updated list of mappings between train describer berths
|
4
|
+
and locations, allowing for TD events to be translated into arrival/departure from location
|
5
|
+
events.
|
6
|
+
See <https://wiki.openraildata.com/index.php/Reference_Data#SMART:_Berth_Stepping_Data>
|
7
|
+
for many more details.
|
8
|
+
|
9
|
+
The SMART module allows for two types of data to be fetched:
|
10
|
+
|
11
|
+
* Step data - This is the data contained in the SMART file and lists the allowable
|
12
|
+
steps between berths. You'll get back an array of all the steps.
|
13
|
+
* Berth data - Given the previously fetched step data you'll get back an hash in a hash
|
14
|
+
of the berths and how they link to other berths. The keys to the outer hash is the signalling
|
15
|
+
area of the TD berth and the key to the inner hash is the berth ID. Fir each berth you can
|
16
|
+
get an array of the steps in both the up and down direction as well as a list of berth IDs
|
17
|
+
reachable in each direction.
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
# Download the SMART data and get the data from it
|
21
|
+
temp_file = RailFeeds::NetworkRail::SMART.fetch
|
22
|
+
step_data = RailFeeds::NetworkRail::SMART.load_file(temp_file.path)
|
23
|
+
|
24
|
+
# Get the SMART data from a previously saved file
|
25
|
+
step_data = RailFeeds::NetworkRail::SMART.load_file('PATH TO FILE.json.gz')
|
26
|
+
|
27
|
+
# Get data from a previously saved and extracted file
|
28
|
+
step_data = RailFeeds::NetworkRail::SMART.load_file('PATH TO FILE.json')
|
29
|
+
|
30
|
+
# Get data by fetching it from the web
|
31
|
+
RailFeeds::NetworkRail::Credentials.configure(
|
32
|
+
username: 'YOUR USERNAME HERE',
|
33
|
+
password: 'YOUR PASSWORD HERE'
|
34
|
+
)
|
35
|
+
step_data = RailFeeds::NetworkRail::SMART.fetch_data
|
36
|
+
|
37
|
+
# Get the baerth data
|
38
|
+
berth_data = RailFeeds::NetworkRail::SMART.build_berths(step_data)
|
39
|
+
```
|
@@ -0,0 +1,138 @@
|
|
1
|
+
# Network Rail Schedule
|
2
|
+
|
3
|
+
The schedule files from Network Rail contain:
|
4
|
+
|
5
|
+
* Details of the TIPLOCs referenced by trains.
|
6
|
+
These are places on the railway for timing purposes.
|
7
|
+
* Associations between various trains (e.g. splitting and joining).
|
8
|
+
* Train schedules, including details about the train and it's journey.
|
9
|
+
|
10
|
+
Every Friday a full extract is performed, you should use this to seed your data and then
|
11
|
+
apply the following update extracts to keep it current. The CIF format files are generally
|
12
|
+
available from about 0100 the morning after (so Saturday for the full extract) whereas the
|
13
|
+
JSON format files take longer to prepare are generally available from 0600.
|
14
|
+
|
15
|
+
You can get various amounts of data at a time, you get to pick between:
|
16
|
+
* Just freight traffic
|
17
|
+
* A specific TOC (you'll need their [TOC code](https://wiki.openraildata.com/index.php/TOC_Codes))
|
18
|
+
* Everything (about 40MB download 400MB extracted file for a full extract)?
|
19
|
+
|
20
|
+
|
21
|
+
## Fetching files
|
22
|
+
|
23
|
+
The RailFeeds::NetworkRail::Schedule::Fetcher class can be used to fetch these files
|
24
|
+
from Network Rail, you'll need to be registered for their data feeds and have
|
25
|
+
subscribed to the schedule you're interested in.
|
26
|
+
|
27
|
+
``` ruby
|
28
|
+
# 1. Require the gem and configure your credentials.
|
29
|
+
require 'rail_feeds'
|
30
|
+
|
31
|
+
RailFeeds::NetworkRail::Credentials.configure(
|
32
|
+
username: 'YOUR USERNAME HERE',
|
33
|
+
password: 'YOUR PASSWORD HERE'
|
34
|
+
)
|
35
|
+
|
36
|
+
# 2. Fetch some files
|
37
|
+
fetcher = RailFeeds::NetworkRail::Schedule::Fetcher.new
|
38
|
+
|
39
|
+
fetcher.fetch_all_full(:cif) do |full_file|
|
40
|
+
...
|
41
|
+
end
|
42
|
+
|
43
|
+
fetcher.fetch_all_update('fri', :cif) do |update_file|
|
44
|
+
...
|
45
|
+
end
|
46
|
+
# Each of the file variables will contain a TempFile which can be used to read
|
47
|
+
# the CIF data (or passed to the parser to make use of). The files will be deleted
|
48
|
+
# at the end of the block.
|
49
|
+
```
|
50
|
+
|
51
|
+
|
52
|
+
## Downloading files
|
53
|
+
|
54
|
+
The RailFeeds::NetworkRail::Schedule::Fetcher class can be used to download these files
|
55
|
+
from Network Rail, you'll need to be registered for their data feeds and have
|
56
|
+
subscribed to the schedule you're interested in.
|
57
|
+
|
58
|
+
``` ruby
|
59
|
+
# 1. Require the gem and configure your credentials.
|
60
|
+
require 'rail_feeds'
|
61
|
+
|
62
|
+
RailFeeds::NetworkRail::Credentials.configure(
|
63
|
+
username: 'YOUR USERNAME HERE',
|
64
|
+
password: 'YOUR PASSWORD HERE'
|
65
|
+
)
|
66
|
+
|
67
|
+
# 2. Download some files
|
68
|
+
fetcher = RailFeeds::NetworkRail::Schedule::Fetcher.new
|
69
|
+
|
70
|
+
fetcher.download_all_full(:cif, 'PATH TO DOWNLOAD TO')
|
71
|
+
fetcher.download_all_update('fri', :cif, 'PATH TO DOWNLOAD TO')
|
72
|
+
|
73
|
+
# Each of the files will be a gzipped version of the CIF formatted schedule.
|
74
|
+
```
|
75
|
+
|
76
|
+
|
77
|
+
## Parsing CIF files
|
78
|
+
|
79
|
+
The RailFeeds::NetworkRail::Schedule::Parser class can be used to
|
80
|
+
parse the previously fetched files. You can parse several files
|
81
|
+
sequentially in one method call. The parser works by calling a
|
82
|
+
user provided proc (specific to each event), whenever it meets
|
83
|
+
the relevant data in the file. Currently only importing CIF files
|
84
|
+
is supported.
|
85
|
+
|
86
|
+
* on_header(parser, header) - For each header (the first record in a file)
|
87
|
+
* on_trailer(parser) - For each trailer (the last record in a file)
|
88
|
+
* on_comment(parser, comment) - For each comment line encountered
|
89
|
+
* on_tiploc_insert(parser, instruction) - Add a new TIPLOC
|
90
|
+
* on_tiploc_amend(parser, instruction) - Amend an existing TIPLOC
|
91
|
+
* on_tiploc_delete(parser, instruction) - Delete an existing TIPLOC
|
92
|
+
* on_association_new(parser, instruction) - Add a new association
|
93
|
+
* on_association_revise(parser, instruction) - Revise an existing association
|
94
|
+
* on_association_delete(parser, instruction) - Delete an existing association
|
95
|
+
* on_train_new(parser, instruction) - Add a new train schedule
|
96
|
+
* on_train_revise(parser, instruction) - Revise an existing train schedule
|
97
|
+
* on_train_delete(parser, instruction) - Delete an existing train schedule
|
98
|
+
|
99
|
+
``` ruby
|
100
|
+
# 3. Parse the fetched files
|
101
|
+
parser = RailFeeds::NetworkRail::Schedule::Parser::CIF.new(
|
102
|
+
YOUR PROCS HERE
|
103
|
+
e.g. on_header: my_header_proc
|
104
|
+
)
|
105
|
+
fetcher.fetch_all_full(:cif) do |full_file|
|
106
|
+
parser.parse_cif full_file
|
107
|
+
end
|
108
|
+
# Your proc(s) can stop the parsing at anytime by calling parser.stop_parsing
|
109
|
+
|
110
|
+
# 4. Print all the header information:
|
111
|
+
header_proc = proc do |parser, header|
|
112
|
+
puts header
|
113
|
+
parser.stop_parsing
|
114
|
+
end
|
115
|
+
parser = RailFeeds::NetworkRail::Schedule::Parser.new(
|
116
|
+
on_header: header_proc
|
117
|
+
)
|
118
|
+
fetcher.fetch_all_full(:cif) do |full_file|
|
119
|
+
parser.parse_cif_file full_file
|
120
|
+
end
|
121
|
+
fetcher.fetch_all_update(:cif) do |update_file|
|
122
|
+
parser.parse_cif_file update_file
|
123
|
+
end
|
124
|
+
```
|
125
|
+
|
126
|
+
|
127
|
+
## Just getting the data
|
128
|
+
The RailFeeds::NetworkRail::Schedule::Data class can be used to avoid
|
129
|
+
directly using the parser and fetcher should you wish. You'll end up
|
130
|
+
with the abillity to get arrays of headers, tiplocs, associations and
|
131
|
+
trains at the expense of everything being loaded into RAM as once.
|
132
|
+
|
133
|
+
``` ruby
|
134
|
+
data = RailFeeds::NetworkRail::Schedule::Data.new
|
135
|
+
data.fetch_data
|
136
|
+
# Uses the fetcher to get the relevant full and/or update files to
|
137
|
+
load the most up to date full schedule.
|
138
|
+
```
|
data/file
ADDED
File without changes
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailFeeds
|
4
|
+
# A Class to store username & password
|
5
|
+
# Can be used to set a global default but create new instances with
|
6
|
+
# specific ones for a specific use.
|
7
|
+
class Credentials
|
8
|
+
# @!attribute [r] username
|
9
|
+
# @return [String] The username to use for authentication.
|
10
|
+
# @!attribute [r] password
|
11
|
+
# @return [String] The password to use for authentication.
|
12
|
+
attr_reader :username, :password
|
13
|
+
|
14
|
+
@username = nil
|
15
|
+
@password = nil
|
16
|
+
|
17
|
+
# Configure default credentials.
|
18
|
+
# @param [String] username
|
19
|
+
# The username to use for authentication.
|
20
|
+
# @param [String] password
|
21
|
+
# The password to use for authentication.
|
22
|
+
def self.configure(username:, password:)
|
23
|
+
@username = username.to_s.clone.freeze
|
24
|
+
@password = password.to_s.clone.freeze
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
# Initialize a new cresential.
|
29
|
+
def initialize(
|
30
|
+
username: self.class.username,
|
31
|
+
password: self.class.password
|
32
|
+
)
|
33
|
+
@username = username.to_s.clone
|
34
|
+
@password = password.to_s.clone
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.username
|
38
|
+
@username.clone
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.password
|
42
|
+
@password.clone
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module RailFeeds
|
6
|
+
# A Module to provide a global logger
|
7
|
+
module Logging
|
8
|
+
def self.included(base)
|
9
|
+
class << base
|
10
|
+
# Provide a logger 'attribute' to a class which defaults to the class logger.
|
11
|
+
def logger
|
12
|
+
@logger || Logging.logger
|
13
|
+
end
|
14
|
+
|
15
|
+
# rubocop:disable Style/TrivialAccessors
|
16
|
+
def logger=(logger)
|
17
|
+
@logger = logger
|
18
|
+
end
|
19
|
+
# rubocop:enable Style/TrivialAccessors
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Provide a logger attribute to an instance which defaults to the global logger.
|
24
|
+
def logger
|
25
|
+
@logger || self.class.logger
|
26
|
+
end
|
27
|
+
|
28
|
+
def logger=(logger)
|
29
|
+
@logger = logger
|
30
|
+
end
|
31
|
+
|
32
|
+
# Global, memoized, lazy initialized instance of a logger
|
33
|
+
def self.logger
|
34
|
+
@logger ||= Logger.new(
|
35
|
+
STDOUT,
|
36
|
+
formatter: formatter,
|
37
|
+
level: Logger::DEBUG
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.logger=(logger)
|
42
|
+
@logger = logger
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.formatter
|
46
|
+
proc do |severity, datetime, progname, message|
|
47
|
+
"#{datetime} #{"#{progname} " unless progname.nil?}#{severity}: #{message}\n"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module RailFeeds
|
6
|
+
module NetworkRail
|
7
|
+
# A module for getting information out of the CORPUS data.
|
8
|
+
module CORPUS
|
9
|
+
Data = Struct.new(
|
10
|
+
:tiploc, :stanox, :crs, :uic, :nlc, :nlc_description, :nlc_short_description
|
11
|
+
)
|
12
|
+
|
13
|
+
# Download the current CORPUS data.
|
14
|
+
# @param [RailFeeds::NetworkRail::Credentials] credentials
|
15
|
+
# @param [String] file
|
16
|
+
# The path to the file to save the .json.gz download in.
|
17
|
+
def self.download(file, credentials: Credentials)
|
18
|
+
client = HTTPClient.new(credentials: credentials)
|
19
|
+
client.download 'ntrod/SupportingFileAuthenticate?type=CORPUS', file
|
20
|
+
end
|
21
|
+
|
22
|
+
# Fetch the current CORPUS data.
|
23
|
+
# @param [RailFeeds::NetworkRail::Credentials] credentials
|
24
|
+
# @return [Tempfile]
|
25
|
+
def self.fetch(credentials: Credentials)
|
26
|
+
client = HTTPClient.new(credentials: credentials)
|
27
|
+
client.fetch 'ntrod/SupportingFileAuthenticate?type=CORPUS'
|
28
|
+
end
|
29
|
+
|
30
|
+
# Load CORPUS data from either a .json or .json.gz file.
|
31
|
+
# @param [String] file The path of the file to open.
|
32
|
+
# @return [Array<RailFeeds::NetworkRail::CORPUS::Data>]
|
33
|
+
def self.load_file(file)
|
34
|
+
Zlib::GzipReader.open(file) do |gz|
|
35
|
+
parse_json gz.read
|
36
|
+
end
|
37
|
+
rescue Zlib::GzipFile::Error
|
38
|
+
parse_json File.read(file)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Load CORPUS data from the internet.
|
42
|
+
# @param [RailFeeds::NetworkRail::Credentials] credentials
|
43
|
+
# The credentials to authenticate with.
|
44
|
+
# @return [Array<RailFeeds::NetworkRail::CORPUS::Data>]
|
45
|
+
def self.fetch_data(credentials: Credentials)
|
46
|
+
client = HTTPClient.new(credentials: credentials)
|
47
|
+
client.fetch_unzipped('ntrod/SupportingFileAuthenticate?type=CORPUS') do |file|
|
48
|
+
break parse_json file.read
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# rubocop:disable Metrics/AbcSize
|
53
|
+
def self.parse_json(json)
|
54
|
+
data = JSON.parse json
|
55
|
+
data['TIPLOCDATA'].map do |item|
|
56
|
+
Data.new(
|
57
|
+
nilify(item['TIPLOC']&.strip),
|
58
|
+
nilify(item['STANOX']&.strip)&.to_i,
|
59
|
+
nilify(item['3ALPHA']&.strip),
|
60
|
+
nilify(item['UIC']&.strip)&.to_i,
|
61
|
+
nilify(item['NLC']&.strip),
|
62
|
+
nilify(item['NLCDESC']&.strip),
|
63
|
+
nilify(item['NLCDESC16']&.strip)
|
64
|
+
)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
# rubocop:enable Metrics/AbcSize
|
68
|
+
private_class_method :parse_json
|
69
|
+
|
70
|
+
def self.nilify(item)
|
71
|
+
return nil if item.nil? || item.empty?
|
72
|
+
item
|
73
|
+
end
|
74
|
+
private_class_method :nilify
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailFeeds
|
4
|
+
module NetworkRail
|
5
|
+
# A Class to store username & password required to access network 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
|
+
# 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
|
+
end
|
21
|
+
end
|
22
|
+
end
|