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.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +31 -0
  5. data/.travis.yml +26 -0
  6. data/CHANGELOG.md +3 -0
  7. data/Gemfile +6 -0
  8. data/Guardfile +25 -0
  9. data/LICENSE.md +32 -0
  10. data/README.md +77 -0
  11. data/Rakefile +3 -0
  12. data/doc/guides/Logging.md +13 -0
  13. data/doc/guides/Network Rail/CORPUS.md +34 -0
  14. data/doc/guides/Network Rail/SMART.md +39 -0
  15. data/doc/guides/Network Rail/Schedule.md +138 -0
  16. data/file +0 -0
  17. data/lib/rail_feeds/credentials.rb +45 -0
  18. data/lib/rail_feeds/logging.rb +51 -0
  19. data/lib/rail_feeds/network_rail/corpus.rb +77 -0
  20. data/lib/rail_feeds/network_rail/credentials.rb +22 -0
  21. data/lib/rail_feeds/network_rail/http_client.rb +57 -0
  22. data/lib/rail_feeds/network_rail/schedule/association.rb +208 -0
  23. data/lib/rail_feeds/network_rail/schedule/data.rb +215 -0
  24. data/lib/rail_feeds/network_rail/schedule/days.rb +95 -0
  25. data/lib/rail_feeds/network_rail/schedule/fetcher.rb +193 -0
  26. data/lib/rail_feeds/network_rail/schedule/header/cif.rb +102 -0
  27. data/lib/rail_feeds/network_rail/schedule/header/json.rb +79 -0
  28. data/lib/rail_feeds/network_rail/schedule/header.rb +22 -0
  29. data/lib/rail_feeds/network_rail/schedule/parser/cif.rb +141 -0
  30. data/lib/rail_feeds/network_rail/schedule/parser/json.rb +87 -0
  31. data/lib/rail_feeds/network_rail/schedule/parser.rb +108 -0
  32. data/lib/rail_feeds/network_rail/schedule/stp_indicator.rb +72 -0
  33. data/lib/rail_feeds/network_rail/schedule/tiploc.rb +100 -0
  34. data/lib/rail_feeds/network_rail/schedule/train_schedule/change_en_route.rb +158 -0
  35. data/lib/rail_feeds/network_rail/schedule/train_schedule/location/intermediate.rb +119 -0
  36. data/lib/rail_feeds/network_rail/schedule/train_schedule/location/origin.rb +91 -0
  37. data/lib/rail_feeds/network_rail/schedule/train_schedule/location/terminating.rb +72 -0
  38. data/lib/rail_feeds/network_rail/schedule/train_schedule/location.rb +76 -0
  39. data/lib/rail_feeds/network_rail/schedule/train_schedule.rb +392 -0
  40. data/lib/rail_feeds/network_rail/schedule.rb +33 -0
  41. data/lib/rail_feeds/network_rail/smart.rb +186 -0
  42. data/lib/rail_feeds/network_rail/stomp_client.rb +77 -0
  43. data/lib/rail_feeds/network_rail.rb +16 -0
  44. data/lib/rail_feeds/version.rb +14 -0
  45. data/lib/rail_feeds.rb +10 -0
  46. data/rail_feeds.gemspec +32 -0
  47. data/spec/fixtures/network_rail/schedule/data/full.yaml +60 -0
  48. data/spec/fixtures/network_rail/schedule/data/starting.yaml +131 -0
  49. data/spec/fixtures/network_rail/schedule/data/update-gap.yaml +10 -0
  50. data/spec/fixtures/network_rail/schedule/data/update-next.yaml +13 -0
  51. data/spec/fixtures/network_rail/schedule/data/update-old.yaml +10 -0
  52. data/spec/fixtures/network_rail/schedule/data/update.yaml +112 -0
  53. data/spec/fixtures/network_rail/schedule/parser/train_create.json +1 -0
  54. data/spec/fixtures/network_rail/schedule/parser/train_delete.json +1 -0
  55. data/spec/fixtures/network_rail/schedule/train_schedule/json-data.yaml +67 -0
  56. data/spec/rail_feeds/credentials_spec.rb +46 -0
  57. data/spec/rail_feeds/logging_spec.rb +81 -0
  58. data/spec/rail_feeds/network_rail/corpus_spec.rb +92 -0
  59. data/spec/rail_feeds/network_rail/credentials_spec.rb +22 -0
  60. data/spec/rail_feeds/network_rail/http_client_spec.rb +88 -0
  61. data/spec/rail_feeds/network_rail/schedule/association_spec.rb +205 -0
  62. data/spec/rail_feeds/network_rail/schedule/data_spec.rb +219 -0
  63. data/spec/rail_feeds/network_rail/schedule/days_shared.rb +99 -0
  64. data/spec/rail_feeds/network_rail/schedule/days_spec.rb +4 -0
  65. data/spec/rail_feeds/network_rail/schedule/fetcher_spec.rb +228 -0
  66. data/spec/rail_feeds/network_rail/schedule/header/cif_spec.rb +72 -0
  67. data/spec/rail_feeds/network_rail/schedule/header/json_spec.rb +51 -0
  68. data/spec/rail_feeds/network_rail/schedule/header_spec.rb +19 -0
  69. data/spec/rail_feeds/network_rail/schedule/parser/cif_spec.rb +197 -0
  70. data/spec/rail_feeds/network_rail/schedule/parser/json_spec.rb +172 -0
  71. data/spec/rail_feeds/network_rail/schedule/parser_spec.rb +34 -0
  72. data/spec/rail_feeds/network_rail/schedule/stp_indicator_shared.rb +49 -0
  73. data/spec/rail_feeds/network_rail/schedule/stp_indicator_spec.rb +4 -0
  74. data/spec/rail_feeds/network_rail/schedule/tiploc_spec.rb +77 -0
  75. data/spec/rail_feeds/network_rail/schedule/train_schedule/change_en_route_spec.rb +121 -0
  76. data/spec/rail_feeds/network_rail/schedule/train_schedule/location/intermediate_spec.rb +95 -0
  77. data/spec/rail_feeds/network_rail/schedule/train_schedule/location/origin_spec.rb +87 -0
  78. data/spec/rail_feeds/network_rail/schedule/train_schedule/location/terminating_spec.rb +81 -0
  79. data/spec/rail_feeds/network_rail/schedule/train_schedule/location_spec.rb +35 -0
  80. data/spec/rail_feeds/network_rail/schedule/train_schedule_spec.rb +284 -0
  81. data/spec/rail_feeds/network_rail/schedule_spec.rb +41 -0
  82. data/spec/rail_feeds/network_rail/smart_spec.rb +194 -0
  83. data/spec/rail_feeds/network_rail/stomp_client_spec.rb +151 -0
  84. data/spec/rail_feeds/network_rail_spec.rb +7 -0
  85. data/spec/rail_feeds_spec.rb +11 -0
  86. data/spec/spec_helper.rb +47 -0
  87. 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