rail_feeds 0.0.1
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 +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
|
+
[](http://badge.fury.io/rb/rail_feeds)
|
|
2
|
+
|
|
3
|
+
Master branch:
|
|
4
|
+
[](http://travis-ci.org/robertgauld/rail_feeds)
|
|
5
|
+
[](https://coveralls.io/r/robertgauld/rail_feeds)
|
|
6
|
+
[](https://codeclimate.com/github/robertgauld/rail_feeds)
|
|
7
|
+
|
|
8
|
+
Staging branch:
|
|
9
|
+
[](http://travis-ci.org/robertgauld/rail_feeds)
|
|
10
|
+
[](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
|