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
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'parser/cif'
|
|
4
|
+
require_relative 'parser/json'
|
|
5
|
+
|
|
6
|
+
module RailFeeds
|
|
7
|
+
module NetworkRail
|
|
8
|
+
module Schedule
|
|
9
|
+
# A parent class for parsing schedule data read from schedule file(s).
|
|
10
|
+
# Children need to implement a parse_line method.
|
|
11
|
+
class Parser
|
|
12
|
+
include Logging
|
|
13
|
+
|
|
14
|
+
# rubocop:disable Metrics/ParameterLists
|
|
15
|
+
# Initialize a new data.
|
|
16
|
+
# @param [Logger, nil] logger
|
|
17
|
+
# The logger for outputting events, if nil the global logger will be used.
|
|
18
|
+
# @param [Proc, #call] on_header
|
|
19
|
+
# The proc to call when the header is received.
|
|
20
|
+
# Passes self and a RailFeeds::NetworkRail::Schedule::Header.
|
|
21
|
+
# @param [Proc, #call] on_tiploc_create
|
|
22
|
+
# The proc to call when a tiploc insertion is received.
|
|
23
|
+
# Passes self and a RailFeeds::NetworkRail::Schedule::Tiploc::Insert.
|
|
24
|
+
# @param [Proc, #call] on_tiploc_update
|
|
25
|
+
# The proc to call when an amendment to an existing tiploc is received.
|
|
26
|
+
# Passes self, tiploc_id and a RailFeeds::NetworkRail::Schedule::Tiploc::Ammend.
|
|
27
|
+
# @param [Proc, #call] on_tiploc_delete
|
|
28
|
+
# The proc to call when an existing tiploc should be deleted.
|
|
29
|
+
# Passes self and a tiploc_id.
|
|
30
|
+
# @param [Proc, #call] on_association_create
|
|
31
|
+
# The proc to call when a new association is received.
|
|
32
|
+
# Passes self and a RailFeeds::NetworkRail::Schedule::Association.
|
|
33
|
+
# @param [Proc, #call] on_association_update
|
|
34
|
+
# The proc to call when a revision to an existing association is received.
|
|
35
|
+
# Passes self and a RailFeeds::NetworkRail::Schedule::Association.
|
|
36
|
+
# @param [Proc, #call] on_association_delete
|
|
37
|
+
# The proc to call when an existing association should be deleted.
|
|
38
|
+
# Passes self and a RailFeeds::NetworkRail::Schedule::Association.
|
|
39
|
+
# @param [Proc, #call] on_train_schedule_create
|
|
40
|
+
# The proc to call when a new train schedule is received.
|
|
41
|
+
# Passes self and a RailFeeds::NetworkRail::Schedule::TrainSchedule::New.
|
|
42
|
+
# @param [Proc, #call] on_train_schedule_update
|
|
43
|
+
# The proc to call when a revision to an existing train schedule is received.
|
|
44
|
+
# Passes self and a RailFeeds::NetworkRail::Schedule::TrainSchedule::Revise.
|
|
45
|
+
# @param [Proc, #call] on_train_schedule_delete
|
|
46
|
+
# The proc to call when an existing train schedule should be deleted.
|
|
47
|
+
# Passes self and a RailFeeds::NetworkRail::Schedule::TrainSchedule::Delete.
|
|
48
|
+
# @param [Proc, #call] on_trailer
|
|
49
|
+
# The proc to call when the trailer (end of file record) is received.
|
|
50
|
+
# Passes self.
|
|
51
|
+
# @param [Proc, #call] on_comment
|
|
52
|
+
# The proc to call when a comment is received.
|
|
53
|
+
# Passes self and a String.
|
|
54
|
+
def initialize(
|
|
55
|
+
logger: nil,
|
|
56
|
+
on_header: nil, on_trailer: nil, on_comment: nil,
|
|
57
|
+
on_tiploc_create: nil, on_tiploc_update: nil, on_tiploc_delete: nil,
|
|
58
|
+
on_association_create: nil, on_association_update: nil,
|
|
59
|
+
on_association_delete: nil, on_train_schedule_create: nil,
|
|
60
|
+
on_train_schedule_update: nil, on_train_schedule_delete: nil
|
|
61
|
+
)
|
|
62
|
+
self.logger = logger unless logger.nil?
|
|
63
|
+
@on_header = on_header
|
|
64
|
+
@on_trailer = on_trailer
|
|
65
|
+
@on_tiploc_create = on_tiploc_create
|
|
66
|
+
@on_tiploc_update = on_tiploc_update
|
|
67
|
+
@on_tiploc_delete = on_tiploc_delete
|
|
68
|
+
@on_association_create = on_association_create
|
|
69
|
+
@on_association_update = on_association_update
|
|
70
|
+
@on_association_delete = on_association_delete
|
|
71
|
+
@on_train_schedule_create = on_train_schedule_create
|
|
72
|
+
@on_train_schedule_update = on_train_schedule_update
|
|
73
|
+
@on_train_schedule_delete = on_train_schedule_delete
|
|
74
|
+
@on_comment = on_comment
|
|
75
|
+
end
|
|
76
|
+
# rubocop:enable Metrics/ParameterLists
|
|
77
|
+
|
|
78
|
+
# Parse the data in CIF file.
|
|
79
|
+
# @param [IO] file
|
|
80
|
+
# The file to load data from.
|
|
81
|
+
def parse_file(file)
|
|
82
|
+
@file_ended = false
|
|
83
|
+
@stop_parsing = false
|
|
84
|
+
|
|
85
|
+
file.each_line do |line|
|
|
86
|
+
parse_line line
|
|
87
|
+
|
|
88
|
+
if @stop_parsing
|
|
89
|
+
logger.debug "Parsing of file #{file} was stopped."
|
|
90
|
+
break
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
fail "File is incomplete. #{file}" unless @stop_parsing || @file_ended
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def parse_line(_line)
|
|
98
|
+
fail 'parse_file MUST be implemented in the child class.'
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Stop parsing the current file.
|
|
102
|
+
def stop_parsing
|
|
103
|
+
@stop_parsing = true
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailFeeds
|
|
4
|
+
module NetworkRail
|
|
5
|
+
module Schedule
|
|
6
|
+
# A collection of methods for working with Short Term Planning indicators.
|
|
7
|
+
# Provides an stp_indicator attribute to the class.
|
|
8
|
+
module STPIndicator
|
|
9
|
+
STP_CIF_MAP = [
|
|
10
|
+
[:permanent, 'P'],
|
|
11
|
+
[:stp_new, 'N'],
|
|
12
|
+
[:stp_overlay, 'O'],
|
|
13
|
+
[:stp_cancellation, 'C']
|
|
14
|
+
].freeze
|
|
15
|
+
private_constant :STP_CIF_MAP
|
|
16
|
+
|
|
17
|
+
def self.included(base)
|
|
18
|
+
base.extend ClassMethods
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @return [Symbol, nil] Whether (and what kind) of STP record this is:
|
|
22
|
+
# * :permanent - This is a permanent (not STP) record
|
|
23
|
+
# * :stp_new - This is a new record (not an overlay)
|
|
24
|
+
# * :stp_overlay - This record should be overlayed on the permanent one
|
|
25
|
+
# * :stp_cancellation - This is an STP cancellation of the permanaent record
|
|
26
|
+
def stp_indicator
|
|
27
|
+
@stp_indicator ||= ' '
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @param [Symbol, #to_s] value Whether (and what kind) of STP record this is:
|
|
31
|
+
# * :permanent, 'P' - This is a permanent (not STP) record
|
|
32
|
+
# * :stp_new, 'N' - This is a new record (not an overlay)
|
|
33
|
+
# * :stp_overlay, 'O' - This record should be overlayed on the permanent one
|
|
34
|
+
# * :stp_cancellation, 'C' - This is an STP cancellation of the permanaent record
|
|
35
|
+
def stp_indicator=(value)
|
|
36
|
+
if STP_CIF_MAP.map(&:last).include?(value.to_s)
|
|
37
|
+
# Convert String / to_s value to relevant Symbol
|
|
38
|
+
value = stp_indicator_from_cif(value)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
unless STP_CIF_MAP.map(&:first).include?(value)
|
|
42
|
+
fail ArgumentError, "value (#{value.inspect}) is invalid, must be any of: " +
|
|
43
|
+
STP_CIF_MAP.flatten.map(&:inspect).join(', ')
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
@stp_indicator = value
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
protected
|
|
50
|
+
|
|
51
|
+
def stp_indicator_to_cif
|
|
52
|
+
self.class.stp_indicator_to_cif stp_indicator
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def stp_indicator_from_cif(value)
|
|
56
|
+
self.class.stp_indicator_from_cif(value)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
module ClassMethods # :nodoc:
|
|
60
|
+
def stp_indicator_to_cif(value)
|
|
61
|
+
STP_CIF_MAP.find { |i| i.first.eql?(value) }&.last
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def stp_indicator_from_cif(value)
|
|
65
|
+
STP_CIF_MAP.find { |i| i.last.eql?(value) }&.first || ' '
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
private_constant :ClassMethods
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailFeeds
|
|
4
|
+
module NetworkRail
|
|
5
|
+
module Schedule
|
|
6
|
+
# A class for holding information about a particular tiploc record
|
|
7
|
+
class Tiploc
|
|
8
|
+
include Comparable
|
|
9
|
+
|
|
10
|
+
# @!attribute [rw] tiploc
|
|
11
|
+
# @return [String] The timing point location code.
|
|
12
|
+
# @!attribute [rw] nlc
|
|
13
|
+
# @return [String] The national location code.
|
|
14
|
+
# @!attribute [rw] nlc_description
|
|
15
|
+
# @return [String] Description of location used in CAPRI.
|
|
16
|
+
# @!attribute [rw] tps_description
|
|
17
|
+
# @return [String] Description of location.
|
|
18
|
+
# @!attribute [rw] stanox
|
|
19
|
+
# @return [Integer] The TOPS location code.
|
|
20
|
+
# @!attribute [rw] crs
|
|
21
|
+
# @return [String] The CRS / 3 Alpha code for the location.
|
|
22
|
+
|
|
23
|
+
attr_accessor :tiploc, :nlc, :nlc_description, :tps_description, :stanox, :crs
|
|
24
|
+
|
|
25
|
+
def initialize(**attributes)
|
|
26
|
+
attributes.each do |attribute, value|
|
|
27
|
+
send "#{attribute}=", value
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Initialize a new tiploc from a CIF file line
|
|
32
|
+
def self.from_cif(line)
|
|
33
|
+
unless %w[TI TA TD].include?(line[0..1])
|
|
34
|
+
fail ArgumentError, "Invalid line:\n#{line}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
new(
|
|
38
|
+
tiploc: line[2..8].strip,
|
|
39
|
+
nlc: Schedule.nil_or_i(line[11..16]),
|
|
40
|
+
nlc_description: line[56..71].strip,
|
|
41
|
+
tps_description: line[18..43].strip,
|
|
42
|
+
stanox: Schedule.nil_or_i(line[44..48]),
|
|
43
|
+
crs: line[53..55].strip
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Initialize a new tiploc from a JSON file line
|
|
48
|
+
def self.from_json(line)
|
|
49
|
+
data = ::JSON.parse(line)['TiplocV1']
|
|
50
|
+
|
|
51
|
+
new(
|
|
52
|
+
tiploc: data['tiploc_code'],
|
|
53
|
+
nlc: Schedule.nil_or_i(data['nalco']),
|
|
54
|
+
stanox: Schedule.nil_or_i(data['stanox']),
|
|
55
|
+
crs: data['crs_code'],
|
|
56
|
+
nlc_description: Schedule.nil_or_strip(data['description']),
|
|
57
|
+
tps_description: data['tps_description']
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def <=>(other)
|
|
62
|
+
hash <=> other&.hash
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def hash
|
|
66
|
+
tiploc.dup
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def to_cif
|
|
70
|
+
format('%-80.80s', [
|
|
71
|
+
'TI',
|
|
72
|
+
format('%-7.7s', tiploc),
|
|
73
|
+
' ',
|
|
74
|
+
format('%-6.6s', nlc),
|
|
75
|
+
' ',
|
|
76
|
+
format('%-26.26s', tps_description),
|
|
77
|
+
format('%-5.5s', stanox),
|
|
78
|
+
' ',
|
|
79
|
+
format('%-3.3s', crs),
|
|
80
|
+
format('%-16.16s', nlc_description)
|
|
81
|
+
].join) + "\n"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def to_json
|
|
85
|
+
{
|
|
86
|
+
'TiplocV1' => {
|
|
87
|
+
'transaction_type' => 'Create',
|
|
88
|
+
'tiploc_code' => tiploc,
|
|
89
|
+
'nalco' => nlc.to_s,
|
|
90
|
+
'stanox' => stanox.to_s,
|
|
91
|
+
'crs_code' => crs,
|
|
92
|
+
'description' => nlc_description,
|
|
93
|
+
'tps_description' => tps_description
|
|
94
|
+
}
|
|
95
|
+
}.to_json
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailFeeds
|
|
4
|
+
module NetworkRail
|
|
5
|
+
module Schedule
|
|
6
|
+
class TrainSchedule
|
|
7
|
+
# A class for holding information about a particular train's change en route
|
|
8
|
+
class ChangeEnRoute
|
|
9
|
+
# @!attribute [rw] tiploc
|
|
10
|
+
# @return [String] The location where the change occurs.
|
|
11
|
+
# @!attribute [rw] tiploc_suffix
|
|
12
|
+
# @return [String]
|
|
13
|
+
# @!attribute [rw] category
|
|
14
|
+
# @return [String] The train's new category.
|
|
15
|
+
# @!attribute [rw] signalling_headcode
|
|
16
|
+
# @return [String, nil] The train's new signalling_headcode.
|
|
17
|
+
# @!attribute [rw] reservation_headcode
|
|
18
|
+
# @return [Integer, nil] The train's new reservation_headcode.
|
|
19
|
+
# @!attribute [rw] service_code
|
|
20
|
+
# @return [String] The train's new service_code.
|
|
21
|
+
# @!attribute [rw] portion_id
|
|
22
|
+
# @return [String, nil] The train's new portion_id.
|
|
23
|
+
# @!attribute [rw] power_type
|
|
24
|
+
# @return [String] The train's new power_type.
|
|
25
|
+
# @!attribute [rw] timing_load
|
|
26
|
+
# @return [String, nil] The train's new timing_load.
|
|
27
|
+
# @!attribute [rw] speed
|
|
28
|
+
# @return [Integer] The train's new speed.
|
|
29
|
+
# @!attribute [rw] operating_characteristics
|
|
30
|
+
# @return [String, nil] The train's new operating_characteristics.
|
|
31
|
+
# @!attribute [rw] seating_class
|
|
32
|
+
# @return [String, nil] The train's new seating_class.
|
|
33
|
+
# @!attribute [rw] sleeping_class
|
|
34
|
+
# @return [String, nil] The train's new sleeping_class.
|
|
35
|
+
# @!attribute [rw] reservations
|
|
36
|
+
# @return [String, nil] The train's new reservations.
|
|
37
|
+
# @!attribute [rw] catering
|
|
38
|
+
# @return [String, nil] The train's new catering.
|
|
39
|
+
# @!attribute [rw] branding
|
|
40
|
+
# @return [String, nil] The train's new branding.
|
|
41
|
+
# @!attribute [rw] uic_code
|
|
42
|
+
# @return [Integer, nil] The train's new uic_code.
|
|
43
|
+
|
|
44
|
+
attr_accessor :tiploc, :tiploc_suffix, :category, :signalling_headcode,
|
|
45
|
+
:reservation_headcode, :service_code, :portion_id, :power_type,
|
|
46
|
+
:timing_load, :speed, :operating_characteristics,
|
|
47
|
+
:seating_class, :sleeping_class, :reservations, :catering,
|
|
48
|
+
:branding, :uic_code
|
|
49
|
+
|
|
50
|
+
def initialize(**attributes)
|
|
51
|
+
attributes.each do |attribute, value|
|
|
52
|
+
send "#{attribute}=", value
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# rubocop:disable Metrics/AbcSize
|
|
57
|
+
# rubocop:disable Metrics/MethodLength
|
|
58
|
+
# Initialize a new change en route from a CIF file line
|
|
59
|
+
def self.from_cif(line)
|
|
60
|
+
fail ArgumentError, "Invalid line:\n#{line}" unless line[0..1].eql?('CR')
|
|
61
|
+
|
|
62
|
+
new(
|
|
63
|
+
tiploc: line[2..8].strip,
|
|
64
|
+
tiploc_suffix: line[9].to_i,
|
|
65
|
+
category: line[10..11].strip,
|
|
66
|
+
signalling_headcode: line[12..15].strip,
|
|
67
|
+
reservation_headcode: Schedule.nil_or_i(line[16..19]),
|
|
68
|
+
service_code: Schedule.nil_or_i(line[21..28]),
|
|
69
|
+
portion_id: Schedule.nil_or_strip(line[29]),
|
|
70
|
+
power_type: line[30..32].strip,
|
|
71
|
+
timing_load: Schedule.nil_or_strip(line[33..36]),
|
|
72
|
+
speed: Schedule.nil_or_i(line[37..39]),
|
|
73
|
+
operating_characteristics: line[40..45].strip,
|
|
74
|
+
seating_class: Schedule.nil_or_strip(line[46]),
|
|
75
|
+
sleeping_class: Schedule.nil_or_strip(line[47]),
|
|
76
|
+
reservations: Schedule.nil_or_strip(line[48]),
|
|
77
|
+
catering: line[50..53].strip,
|
|
78
|
+
branding: Schedule.nil_or_strip(line[54..57]),
|
|
79
|
+
uic_code: Schedule.nil_or_strip(line[62..66])
|
|
80
|
+
)
|
|
81
|
+
end
|
|
82
|
+
# rubocop:enable Metrics/AbcSize
|
|
83
|
+
# rubocop:enable Metrics/MethodLength
|
|
84
|
+
|
|
85
|
+
# rubocop:disable Metrics/AbcSize
|
|
86
|
+
# rubocop:disable Metrics/MethodLength
|
|
87
|
+
# Apply these changes to a train.
|
|
88
|
+
# @param [RailFeeds::NetworkRail::Schedule::TrainSchedule] train
|
|
89
|
+
# The train to apply the changes to.
|
|
90
|
+
# @return [RailFeeds::NetworkRail::Schedule::TrainSchedule]
|
|
91
|
+
# The train the changes were applied to.
|
|
92
|
+
def apply_to(train)
|
|
93
|
+
train.category = category
|
|
94
|
+
train.signalling_headcode = signalling_headcode
|
|
95
|
+
train.reservation_headcode = reservation_headcode
|
|
96
|
+
train.service_code = service_code
|
|
97
|
+
train.portion_id = portion_id
|
|
98
|
+
train.power_type = power_type
|
|
99
|
+
train.timing_load = timing_load
|
|
100
|
+
train.speed = speed
|
|
101
|
+
train.operating_characteristics = operating_characteristics
|
|
102
|
+
train.seating_class = seating_class
|
|
103
|
+
train.sleeping_class = sleeping_class
|
|
104
|
+
train.reservations = reservations
|
|
105
|
+
train.catering = catering
|
|
106
|
+
train.branding = branding
|
|
107
|
+
train.uic_code = uic_code
|
|
108
|
+
train
|
|
109
|
+
end
|
|
110
|
+
# rubocop:enable Metrics/AbcSize
|
|
111
|
+
# rubocop:enable Metrics/MethodLength
|
|
112
|
+
|
|
113
|
+
def ==(other)
|
|
114
|
+
hash == other&.hash
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# rubocop:disable Metrics/AbcSize
|
|
118
|
+
# rubocop:disable Metrics/MethodLength
|
|
119
|
+
def to_cif
|
|
120
|
+
format('%-80.80s', [
|
|
121
|
+
'CR',
|
|
122
|
+
format('%-7.7s', tiploc),
|
|
123
|
+
format('%-1.1s', tiploc_suffix),
|
|
124
|
+
format('%-2.2s', category),
|
|
125
|
+
format('%-4.4s', signalling_headcode),
|
|
126
|
+
format('%-4.4s', reservation_headcode),
|
|
127
|
+
' ',
|
|
128
|
+
format('%-8.8s', service_code),
|
|
129
|
+
format('%-1.1s', portion_id),
|
|
130
|
+
format('%-3.3s', power_type),
|
|
131
|
+
format('%-4.4s', timing_load),
|
|
132
|
+
format('%-3.3s', speed),
|
|
133
|
+
format('%-6.6s', operating_characteristics),
|
|
134
|
+
format('%-1.1s', seating_class),
|
|
135
|
+
format('%-1.1s', sleeping_class),
|
|
136
|
+
format('%-1.1s', reservations),
|
|
137
|
+
' ',
|
|
138
|
+
format('%-4.4s', catering),
|
|
139
|
+
format('%-4.4s', branding),
|
|
140
|
+
' ',
|
|
141
|
+
format('%-5.5s', uic_code)
|
|
142
|
+
].join) + "\n"
|
|
143
|
+
end
|
|
144
|
+
# rubocop:enable Metrics/AbcSize
|
|
145
|
+
# rubocop:enable Metrics/MethodLength
|
|
146
|
+
|
|
147
|
+
def hash
|
|
148
|
+
"#{tiploc}-#{tiploc_suffix}"
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def to_hash_for_json
|
|
152
|
+
nil
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailFeeds
|
|
4
|
+
module NetworkRail
|
|
5
|
+
module Schedule
|
|
6
|
+
class TrainSchedule
|
|
7
|
+
class Location
|
|
8
|
+
# A class for holding information about a particular train's particular location
|
|
9
|
+
class Intermediate < Location
|
|
10
|
+
# @!attribute [rw] line
|
|
11
|
+
# @return [String]
|
|
12
|
+
# @!attribute [rw] path
|
|
13
|
+
# @return [String]
|
|
14
|
+
# @!attribute [rw] scheduled_arrival
|
|
15
|
+
# @return [String] The scheduled time for arriving at the location.
|
|
16
|
+
# @!attribute [rw] scheduled_pass
|
|
17
|
+
# @return [String] The scheduled time for passing the location.
|
|
18
|
+
# @!attribute [rw] scheduled_departure
|
|
19
|
+
# @return [String] The sheduled time for departing from the location.
|
|
20
|
+
# @!attribute [rw] public_arrival
|
|
21
|
+
# @return [String] The public arrival time (HHMM).
|
|
22
|
+
# @!attribute [rw] public_departure
|
|
23
|
+
# @return [String] The public departure time (HHMM).
|
|
24
|
+
# @!attribute [rw] engineering_allowance
|
|
25
|
+
# @return [Float] Number of minutes.
|
|
26
|
+
# @!attribute [rw] pathing_allowance
|
|
27
|
+
# @return [Float] Number of minutes.
|
|
28
|
+
# @!attribute [rw] performance_allowance
|
|
29
|
+
# @return [Float] Number of minutes.
|
|
30
|
+
|
|
31
|
+
attr_accessor :line, :path,
|
|
32
|
+
:scheduled_arrival, :scheduled_departure, :scheduled_pass,
|
|
33
|
+
:public_arrival, :public_departure,
|
|
34
|
+
:engineering_allowance, :pathing_allowance,
|
|
35
|
+
:performance_allowance
|
|
36
|
+
|
|
37
|
+
def initialize(**attributes)
|
|
38
|
+
attributes.each do |attribute, value|
|
|
39
|
+
send "#{attribute}=", value
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# rubocop:disable Metrics/AbcSize
|
|
44
|
+
# rubocop:disable Metrics/MethodLength
|
|
45
|
+
# Initialize a new intermediate location from a CIF file line
|
|
46
|
+
def self.from_cif(line)
|
|
47
|
+
fail ArgumentError, "Invalid line:\n#{line}" unless line[0..1].eql?('LI')
|
|
48
|
+
|
|
49
|
+
new(
|
|
50
|
+
tiploc: line[2..8].strip,
|
|
51
|
+
tiploc_suffix: line[9].to_i,
|
|
52
|
+
scheduled_arrival: line[10..14].strip,
|
|
53
|
+
scheduled_departure: line[15..19].strip,
|
|
54
|
+
scheduled_pass: line[20..24].strip,
|
|
55
|
+
public_arrival: line[25..28].strip,
|
|
56
|
+
public_departure: line[29..32].strip,
|
|
57
|
+
platform: line[33..35].strip,
|
|
58
|
+
line: line[36..38].strip,
|
|
59
|
+
path: line[39..41].strip,
|
|
60
|
+
activity: line[42..53].strip,
|
|
61
|
+
engineering_allowance: parse_allowance(line[54..55].strip),
|
|
62
|
+
pathing_allowance: parse_allowance(line[56..57].strip),
|
|
63
|
+
performance_allowance: parse_allowance(line[58..59].strip)
|
|
64
|
+
)
|
|
65
|
+
end
|
|
66
|
+
# rubocop:enable Metrics/AbcSize
|
|
67
|
+
# rubocop:enable Metrics/MethodLength
|
|
68
|
+
|
|
69
|
+
# rubocop:disable Metrics/AbcSize
|
|
70
|
+
# rubocop:disable Metrics/MethodLength
|
|
71
|
+
def to_cif
|
|
72
|
+
format('%-80.80s', [
|
|
73
|
+
'LI',
|
|
74
|
+
format('%-7.7s', tiploc),
|
|
75
|
+
format('%-1.1s', tiploc_suffix),
|
|
76
|
+
format('%-5.5s', scheduled_arrival),
|
|
77
|
+
format('%-5.5s', scheduled_departure),
|
|
78
|
+
format('%-5.5s', scheduled_pass),
|
|
79
|
+
format('%-4.4s', public_arrival),
|
|
80
|
+
format('%-4.4s', public_departure),
|
|
81
|
+
format('%-3.3s', platform),
|
|
82
|
+
format('%-3.3s', line),
|
|
83
|
+
format('%-3.3s', path),
|
|
84
|
+
format('%-12.12s', activity),
|
|
85
|
+
format('%-2.2s', allowance_cif(engineering_allowance)),
|
|
86
|
+
format('%-2.2s', allowance_cif(pathing_allowance)),
|
|
87
|
+
format('%-2.2s', allowance_cif(performance_allowance))
|
|
88
|
+
].join) + "\n"
|
|
89
|
+
end
|
|
90
|
+
# rubocop:enable Metrics/AbcSize
|
|
91
|
+
# rubocop:enable Metrics/MethodLength
|
|
92
|
+
|
|
93
|
+
# rubocop:disable Metrics/MethodLength
|
|
94
|
+
def to_hash_for_json
|
|
95
|
+
{
|
|
96
|
+
location_type: 'LI',
|
|
97
|
+
record_identity: 'LI',
|
|
98
|
+
tiploc_code: tiploc,
|
|
99
|
+
tiploc_instance: tiploc_suffix,
|
|
100
|
+
arrival: scheduled_arrival,
|
|
101
|
+
departure: scheduled_departure,
|
|
102
|
+
pass: scheduled_pass,
|
|
103
|
+
public_arrival: public_arrival,
|
|
104
|
+
public_departure: public_departure,
|
|
105
|
+
platform: platform,
|
|
106
|
+
line: line,
|
|
107
|
+
path: path,
|
|
108
|
+
engineering_allowance: allowance_json(engineering_allowance),
|
|
109
|
+
pathing_allowance: allowance_json(pathing_allowance),
|
|
110
|
+
performance_allowance: allowance_json(performance_allowance)
|
|
111
|
+
}
|
|
112
|
+
end
|
|
113
|
+
# rubocop:enable Metrics/MethodLength
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailFeeds
|
|
4
|
+
module NetworkRail
|
|
5
|
+
module Schedule
|
|
6
|
+
class TrainSchedule
|
|
7
|
+
class Location
|
|
8
|
+
# A class for holding information about a particular train's origin location
|
|
9
|
+
class Origin < Location
|
|
10
|
+
# @!attribute [rw] line
|
|
11
|
+
# @return [String]
|
|
12
|
+
# @!attribute [rw] scheduled_departure
|
|
13
|
+
# @return [String] The sheduled time for departing from the location.
|
|
14
|
+
# @!attribute [rw] public_departure
|
|
15
|
+
# @return [String] The public departure time (HHMM).
|
|
16
|
+
# @!attribute [rw] engineering_allowance
|
|
17
|
+
# @return [Float] Number of minutes.
|
|
18
|
+
# @!attribute [rw] pathing_allowance
|
|
19
|
+
# @return [Float] Number of minutes.
|
|
20
|
+
# @!attribute [rw] performance_allowance
|
|
21
|
+
# @return [Float] Number of minutes.
|
|
22
|
+
|
|
23
|
+
attr_accessor :scheduled_departure, :public_departure, :line,
|
|
24
|
+
:engineering_allowance, :pathing_allowance,
|
|
25
|
+
:performance_allowance
|
|
26
|
+
|
|
27
|
+
def initialize(**attributes)
|
|
28
|
+
attributes.each do |attribute, value|
|
|
29
|
+
send "#{attribute}=", value
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# rubocop:disable Metrics/AbcSize
|
|
34
|
+
# Initialize a new origin location from a CIF file line
|
|
35
|
+
def self.from_cif(line)
|
|
36
|
+
fail ArgumentError, "Invalid line:\n#{line}" unless line[0..1].eql?('LO')
|
|
37
|
+
|
|
38
|
+
new(
|
|
39
|
+
tiploc: line[2..8].strip,
|
|
40
|
+
tiploc_suffix: line[9].to_i,
|
|
41
|
+
scheduled_departure: line[10..14].strip,
|
|
42
|
+
public_departure: line[15..18].strip,
|
|
43
|
+
platform: line[19..21].strip,
|
|
44
|
+
line: line[22..24].strip,
|
|
45
|
+
activity: line[29..40].strip,
|
|
46
|
+
engineering_allowance: parse_allowance(line[25..26].strip),
|
|
47
|
+
pathing_allowance: parse_allowance(line[27..28].strip),
|
|
48
|
+
performance_allowance: parse_allowance(line[41..42].strip)
|
|
49
|
+
)
|
|
50
|
+
end
|
|
51
|
+
# rubocop:enable Metrics/AbcSize
|
|
52
|
+
|
|
53
|
+
# rubocop:disable Metrics/AbcSize
|
|
54
|
+
def to_cif
|
|
55
|
+
format('%-80.80s', [
|
|
56
|
+
'LO',
|
|
57
|
+
format('%-7.7s', tiploc),
|
|
58
|
+
format('%-1.1s', tiploc_suffix),
|
|
59
|
+
format('%-5.5s', scheduled_departure),
|
|
60
|
+
format('%-4.4s', public_departure),
|
|
61
|
+
format('%-3.3s', platform),
|
|
62
|
+
format('%-3.3s', line),
|
|
63
|
+
format('%-2.2s', allowance_cif(engineering_allowance)),
|
|
64
|
+
format('%-2.2s', allowance_cif(pathing_allowance)),
|
|
65
|
+
format('%-12.12s', activity),
|
|
66
|
+
format('%-2.2s', allowance_cif(performance_allowance))
|
|
67
|
+
].join) + "\n"
|
|
68
|
+
end
|
|
69
|
+
# rubocop:enable Metrics/AbcSize
|
|
70
|
+
|
|
71
|
+
def to_hash_for_json
|
|
72
|
+
{
|
|
73
|
+
location_type: 'LO',
|
|
74
|
+
record_identity: 'LO',
|
|
75
|
+
tiploc_code: tiploc,
|
|
76
|
+
tiploc_instance: tiploc_suffix,
|
|
77
|
+
departure: scheduled_departure,
|
|
78
|
+
public_departure: public_departure,
|
|
79
|
+
platform: platform,
|
|
80
|
+
line: line,
|
|
81
|
+
engineering_allowance: allowance_json(engineering_allowance),
|
|
82
|
+
pathing_allowance: allowance_json(pathing_allowance),
|
|
83
|
+
performance_allowance: allowance_json(performance_allowance)
|
|
84
|
+
}
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|