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
@@ -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
|