atco 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 91d4d697f6d487218aa3def133f0104257141ed8fb18b93be2c3f0c52ac92a6e
4
+ data.tar.gz: 213d51b686a0076c69f26b6d18173dd2b767eaf24db17f7e0cdc011406b94705
5
+ SHA512:
6
+ metadata.gz: fb0ccef50c6a0490c9b87b0b01a7179bec8ca755d594f52193ef6220ef6733e2c8ed600f46043c3a0a38038f3290a8687f1828adfe893dac7dad5c7413b23c89
7
+ data.tar.gz: 6ba15c31b4cfb1873577af0fe50c62c6325780d9f9c3c6ddb124cfe91397dd2808382757f1198f492ea6fbbe2a21131e010b49ac80a757f33041a3ff57db1d9f
@@ -2,11 +2,14 @@
2
2
 
3
3
  ATCO-CIF is the format of choice for UK public transport authorities. This is a ruby library that reads **.cif** files and gives you JSON back.
4
4
 
5
+ * ATCO (Association of Transport Coordinating Officers)
6
+ * CIF (Common Interface File)
7
+
5
8
  * **Official spec:** [http://www.pti.org.uk/CIF/atco-cif-spec.pdf](http://www.pti.org.uk/CIF/atco-cif-spec.pdf)
6
9
 
7
10
  ### USAGE
8
11
 
9
- Currently this library is under-development and has several things left to do before it is perfect (see the [todo.mdown](http://github.com/davidjrice/atco/blob/master/todo.mdown) list ).
12
+ Currently this library is under-development and has several things left to do before it is perfect (see the [todo.md](http://github.com/davidjrice/atco/blob/master/TODO.md) list ).
10
13
 
11
14
  * clone this library
12
15
  * start an irb session
@@ -14,14 +17,21 @@ Currently this library is under-development and has several things left to do be
14
17
 
15
18
  Code example, for more detailed internal api usage see the spec files.
16
19
 
17
- require 'lib/atco'
18
-
19
- result = Atco.parse('filename.cif')
20
- result = Atco.parse('SVRTMAO009A-20091005.cif) # an example data file
21
-
22
- => {
23
- :header => {...},
24
- :locations => [...],
25
- :journies => {...}
26
- }
27
-
20
+
21
+ ```ruby
22
+ gem install atco
23
+ irb
24
+
25
+
26
+ require 'rubygems
27
+ require 'atco'
28
+
29
+ result = Atco.parse('filename.cif')
30
+ result = Atco.parse('SVRTMAO009A-20091005.cif) # an example data file in the repo
31
+
32
+ => {
33
+ header: {…},
34
+ locations: […],
35
+ journies: {…}
36
+ }
37
+ ```
data/Rakefile CHANGED
@@ -1,14 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
1
6
  begin
2
- require 'jeweler'
3
- Jeweler::Tasks.new do |s|
4
- s.name = "atco"
5
- s.summary = "Simple and opinionated library for parsing ATCO-CIF files with Ruby."
6
- s.email = "me@davidjrice.co.uk"
7
- s.homepage = "http://github.com/davidjrice/atco"
8
- s.description = "Simple and opinionated library for parsing ATCO-CIF files with Ruby."
9
- s.authors = ["David Rice"]
10
- s.files = FileList["[A-Z]*", "{bin,generators,lib,test}/**/*", 'lib/jeweler/templates/.gitignore']
11
- end
7
+ RSpec::Core::RakeTask.new(:spec)
12
8
  rescue LoadError
13
- puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install jeweler"
14
- end
9
+ puts 'RSpec, or one of its dependencies, is not available. Install it with: bundle install'
10
+ end
11
+
12
+ task default: :spec
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 1.0.0
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Atco
4
+ class Journey
5
+ attr_accessor :vehicle_type, :registration_number, :identifier, :operator, :route_number, :first_date_of_operation,
6
+ :running_board, :last_date_of_operation, :school_term_time, :route_direction, :bank_holidays, :stops
7
+
8
+ def initialize(data)
9
+ @mondays = parse_boolean_int data[:operates_on_mondays]
10
+ @tuesdays = parse_boolean_int data[:operates_on_tuesdays]
11
+ @wednesdays = parse_boolean_int data[:operates_on_wednesdays]
12
+ @thursdays = parse_boolean_int data[:operates_on_thursdays]
13
+ @fridays = parse_boolean_int data[:operates_on_fridays]
14
+ @saturdays = parse_boolean_int data[:operates_on_saturdays]
15
+ @sundays = parse_boolean_int data[:operates_on_sundays]
16
+
17
+ @vehicle_type = data[:vehicle_type]
18
+ @registration_number = data[:registration_number]
19
+ @identifier = data[:unique_journey_identifier]
20
+ @operator = data[:operator]
21
+ @route_number = data[:route_number]
22
+ @route_direction = data[:route_direction]
23
+ @first_date_of_operation = data[:first_date_of_operation]
24
+ @last_date_of_operation = data[:last_date_of_operation]
25
+ @running_board = data[:running_board]
26
+ @school_term_time = data[:school_term_time]
27
+ @bank_holidays = data[:bank_holidays]
28
+
29
+ @stops = []
30
+ # stops.each do |s|
31
+ # @stops << Stop.new(s)
32
+ # end
33
+ end
34
+
35
+ def mondays?
36
+ @mondays
37
+ end
38
+
39
+ def tuesdays?
40
+ @tuesdays
41
+ end
42
+
43
+ def wednesdays?
44
+ @wednesdays
45
+ end
46
+
47
+ def thursdays?
48
+ @thursdays
49
+ end
50
+
51
+ def fridays?
52
+ @fridays
53
+ end
54
+
55
+ def saturdays?
56
+ @saturdays
57
+ end
58
+
59
+ def sundays?
60
+ @sundays
61
+ end
62
+
63
+ def parse_boolean_int(string)
64
+ string && string == '1' ? true : false
65
+ end
66
+
67
+ def to_json(*args)
68
+ {
69
+ vehicle_type: @vehicle_type,
70
+ registration_number: @registration_number,
71
+ identifier: @identifier,
72
+ operator: @operator,
73
+ route_number: @route_number,
74
+ first_date_of_operation: @first_date_of_operation,
75
+ running_board: @running_board,
76
+ last_date_of_operation: @last_date_of_operation,
77
+ school_term_time: @school_term_time,
78
+ route_direction: @route_direction,
79
+ bank_holidays: @bank_holidays,
80
+ stops: @stops
81
+ }.to_json(*args)
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Atco
4
+ class Location
5
+ attr_accessor :name, :identifier, :easting, :northing, :gazeteer_code
6
+
7
+ def initialize(location_header, additional_location_information)
8
+ @name = location_header[:full_location]
9
+ @identifier = location_header[:record_identity]
10
+ @easting = additional_location_information[:grid_reference_easting]
11
+ @northing = additional_location_information[:grid_reference_northing]
12
+ @gazeteer_code = location_header[:gazetteer_code]
13
+ end
14
+
15
+ def to_json(*a)
16
+ {
17
+ name: @name,
18
+ identifier: @identifier,
19
+ easting: @easting,
20
+ northing: @northing,
21
+ gazeteer_code: @gazeteer_code
22
+ }.to_json(*a)
23
+ end
24
+ end
25
+ end
data/lib/atco/stop.rb ADDED
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Atco
4
+ class Stop
5
+ attr_accessor :bay_number, :location, :timing_point_indicator, :fare_stage_indicator, :published_departure_time,
6
+ :record_identity
7
+
8
+ def origin?
9
+ @record_identity == 'QO'
10
+ end
11
+
12
+ def intermediate?
13
+ @record_identity == 'QI'
14
+ end
15
+
16
+ def destination?
17
+ @record_identity == 'QT'
18
+ end
19
+
20
+ def initialize(data)
21
+ @bay_number = data[:bay_number]
22
+ @location = data[:location]
23
+ @timing_point_indicator = data[:timing_point_indicator]
24
+ @fare_stage_indicator = data[:fare_stage_indicator]
25
+ @published_departure_time = data[:published_departure_time]
26
+ @record_identity = data[:record_identity]
27
+ end
28
+
29
+ def to_json(*args)
30
+ {
31
+ record_identity: @record_identity,
32
+ location: @location,
33
+ published_departure_time: @published_departure_time,
34
+ timing_point_indicator: @timing_point_indicator,
35
+ fare_stage_indicator: @fare_stage_indicator,
36
+ bay_number: @bay_number
37
+ }.to_json(*args)
38
+ end
39
+ end
40
+ end
data/lib/atco.rb CHANGED
@@ -1,180 +1,182 @@
1
- $:.unshift(File.dirname(__FILE__)) unless
2
- $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.unshift(File.dirname(__FILE__)) unless
4
+ $LOAD_PATH.include?(File.dirname(__FILE__)) || $LOAD_PATH.include?(__dir__)
3
5
 
4
6
  require 'open3'
5
- require 'tempfile'
6
- require 'location'
7
+ require 'tempfile'
8
+ require 'atco/location'
9
+ require 'atco/journey'
10
+ require 'atco/stop'
7
11
 
8
12
  module Atco
9
13
  VERSION = '0.0.1'
10
-
14
+
11
15
  class << self
12
-
13
16
  @path = nil
14
17
  @@methods = {
15
- :bank_holiday => 'QH',
16
- :operator => 'QP',
17
- :additional_location_info => 'QB',
18
- :location => 'QL',
19
- :destination => 'QT',
20
- :intermediate => 'QI',
21
- :origin => 'QO',
22
- :journey_header => 'QS'
18
+ bank_holiday: 'QH',
19
+ operator: 'QP',
20
+ additional_location_info: 'QB',
21
+ location: 'QL',
22
+ destination: 'QT',
23
+ intermediate: 'QI',
24
+ origin: 'QO',
25
+ journey_header: 'QS'
23
26
  }
24
-
27
+
25
28
  def parse(file)
26
29
  @path = File.expand_path(file)
27
30
  data = File.readlines(@path)
28
-
31
+
29
32
  objects = []
30
33
  current_journey = nil
31
34
  current_location = nil
32
35
  locations = []
33
36
  journeys = {}
34
37
  header = nil
35
-
38
+
36
39
  data.each do |line|
37
40
  if line == data.first
38
41
  header = parse_header(line)
39
42
  next
40
43
  end
41
- @@methods.each do |method,identifier|
42
- object = self.send("parse_#{method}", line)
43
- if object[:record_identity] && object[:record_identity] == identifier
44
- current_journey = object if object[:record_identity] && object[:record_identity] == @@methods[:journey_header]
45
- if object[:record_identity] && ( object[:record_identity] == @@methods[:location] || object[:record_identity] == @@methods[:additional_location_info] )
46
- if object[:record_identity] == @@methods[:location]
47
- current_location = object
48
- else
49
- locations << Location.new(current_location, object)
50
- end
44
+ @@methods.each do |method, identifier|
45
+ object = send("parse_#{method}", line)
46
+ next unless object[:record_identity] && object[:record_identity] == identifier
47
+
48
+ current_journey = object if object[:record_identity] && object[:record_identity] == @@methods[:journey_header]
49
+ if object[:record_identity] && (object[:record_identity] == @@methods[:location] || object[:record_identity] == @@methods[:additional_location_info])
50
+ if object[:record_identity] == @@methods[:location]
51
+ current_location = object
52
+ else
53
+ locations << Location.new(current_location, object)
51
54
  end
55
+ end
52
56
 
53
- if current_journey
54
- if journeys[current_journey[:unique_journey_identifier]]
55
- journeys[current_journey[:unique_journey_identifier]] << object
56
- else
57
- journeys[current_journey[:unique_journey_identifier]] = [object]
58
- end
57
+ if current_journey
58
+ if journeys[current_journey[:unique_journey_identifier]]
59
+ journeys[current_journey[:unique_journey_identifier]].stops << Stop.new(object)
60
+ else
61
+ journeys[current_journey[:unique_journey_identifier]] = Journey.new(object)
59
62
  end
60
- objects << object
61
63
  end
64
+ objects << object
62
65
  end
63
66
  end
64
- return {:header => header, :locations => locations, :journeys => journeys}
67
+ { header: header, locations: locations, journeys: journeys }
65
68
  end
66
-
69
+
67
70
  def parse_header(string)
68
71
  {
69
- :file_type => string[0,8],
70
- :version => "#{string[8,2].to_i}.#{string[10,2].to_i}",
71
- :file_originator => string[12,32].strip!,
72
- :source_product => string[44,16].strip!,
73
- :production_datetime => string[60,14]
74
- }
72
+ file_type: string[0, 8],
73
+ version: "#{string[8, 2].to_i}.#{string[10, 2].to_i}",
74
+ file_originator: string[12, 32].strip!,
75
+ source_product: string[44, 16].strip!,
76
+ production_datetime: string[60, 14]
77
+ }
75
78
  end
76
-
79
+
77
80
  def parse_bank_holiday(string)
78
81
  {
79
- :record_identity => string[0,2],
80
- :transaction_type => string[2,1],
81
- :date_of_bank_holiday => string[3,8]
82
+ record_identity: string[0, 2],
83
+ transaction_type: string[2, 1],
84
+ date_of_bank_holiday: string[3, 8]
82
85
  }
83
86
  end
84
-
87
+
85
88
  def parse_operator(string)
86
89
  {
87
- :record_identity => string[0,2],
88
- :transaction_type => string[2,1],
89
- :operator => parse_value(string[3,4]),
90
- :operator_short_form => parse_value(string[7,24]),
91
- :operator_legal_name => parse_value(string[31,48])
90
+ record_identity: string[0, 2],
91
+ transaction_type: string[2, 1],
92
+ operator: parse_value(string[3, 4]),
93
+ operator_short_form: parse_value(string[7, 24]),
94
+ operator_legal_name: parse_value(string[31, 48])
92
95
  }
93
96
  end
94
97
 
95
98
  def parse_additional_location_info(string)
96
99
  {
97
- :record_identity => string[0,2],
98
- :transaction_type => string[2,1],
99
- :location => string[3,12].strip,
100
- :grid_reference_easting => parse_value(string[15,8]),
101
- :grid_reference_northing => parse_value(string[23,8])
100
+ record_identity: string[0, 2],
101
+ transaction_type: string[2, 1],
102
+ location: string[3, 12].strip,
103
+ grid_reference_easting: parse_value(string[15, 8]),
104
+ grid_reference_northing: parse_value(string[23, 8])
102
105
  }
103
106
  end
104
107
 
105
108
  def parse_location(string)
106
109
  {
107
- :record_identity => string[0,2],
108
- :transaction_type => string[2,1],
109
- :location => parse_value(string[3,12]),
110
- :full_location => parse_value(string[15,48]),
111
- :gazetteer_code => string[63,1]
110
+ record_identity: string[0, 2],
111
+ transaction_type: string[2, 1],
112
+ location: parse_value(string[3, 12]),
113
+ full_location: parse_value(string[15, 48]),
114
+ gazetteer_code: string[63, 1]
112
115
  }
113
116
  end
114
117
 
115
118
  def parse_destination(string)
116
119
  {
117
- :record_identity => string[0,2],
118
- :location => string[2,12],
119
- :published_arrival_time => string[14,4],
120
- :bay_number => parse_value(string[18,3]),
121
- :timing_point_indicator => string[21,2],
122
- :fare_stage_indicator => string[23,2]
120
+ record_identity: string[0, 2],
121
+ location: string[2, 12],
122
+ published_arrival_time: string[14, 4],
123
+ bay_number: parse_value(string[18, 3]),
124
+ timing_point_indicator: string[21, 2],
125
+ fare_stage_indicator: string[23, 2]
123
126
  }
124
127
  end
125
128
 
126
129
  def parse_intermediate(string)
127
130
  {
128
- :record_identity => string[0,2],
129
- :location => string[2,12],
130
- :published_arrival_time => string[14,4],
131
- :published_departure_time => string[18,4],
132
- :activity_flag => string[22,1],
133
- :bay_number => parse_value(string[23,3]),
134
- :timing_point_indicator => string[26,2],
135
- :fare_stage_indicator => string[28,2]
131
+ record_identity: string[0, 2],
132
+ location: string[2, 12],
133
+ published_arrival_time: string[14, 4],
134
+ published_departure_time: string[18, 4],
135
+ activity_flag: string[22, 1],
136
+ bay_number: parse_value(string[23, 3]),
137
+ timing_point_indicator: string[26, 2],
138
+ fare_stage_indicator: string[28, 2]
136
139
  }
137
140
  end
138
141
 
139
142
  def parse_origin(string)
140
143
  {
141
- :record_identity => string[0,2],
142
- :location => string[2,12],
143
- :published_departure_time => string[14,4],
144
- :bay_number => parse_value(string[18,3]),
145
- :timing_point_indicator => string[21,2],
146
- :fare_stage_indicator => string[23,2]
144
+ record_identity: string[0, 2],
145
+ location: string[2, 12],
146
+ published_departure_time: string[14, 4],
147
+ bay_number: parse_value(string[18, 3]),
148
+ timing_point_indicator: string[21, 2],
149
+ fare_stage_indicator: string[23, 2]
147
150
  }
148
151
  end
149
152
 
150
153
  def parse_journey_header(string)
151
154
  {
152
- :record_identity => string[0,2],
153
- :transaction_type => string[2,1],
154
- :operator => string[3,4].strip,
155
- :unique_journey_identifier => string[7,6],
156
- :first_date_of_operation => parse_value(string[13,8]),
157
- :last_date_of_operation => parse_value(string[21,8]),
158
- :operates_on_mondays => string[29,1],
159
- :operates_on_tuesdays => string[30,1],
160
- :operates_on_wednesdays => string[31,1],
161
- :operates_on_thursdays => string[32,1],
162
- :operates_on_fridays => string[33,1],
163
- :operates_on_saturdays => string[34,1],
164
- :operates_on_sundays => string[35,1],
165
- :school_term_time => parse_value(string[36,1]),
166
- :bank_holidays => parse_value(string[37,1]),
167
- :route_number => parse_value(string[38,4]),
168
- :running_board => parse_value(string[42,6]),
169
- :vehicle_type => parse_value(string[48,8]),
170
- :registration_number => parse_value(string[56,8]),
171
- :route_direction => string[64,1]
155
+ record_identity: string[0, 2],
156
+ transaction_type: string[2, 1],
157
+ operator: string[3, 4].strip,
158
+ unique_journey_identifier: string[7, 6],
159
+ first_date_of_operation: parse_value(string[13, 8]),
160
+ last_date_of_operation: parse_value(string[21, 8]),
161
+ operates_on_mondays: string[29, 1],
162
+ operates_on_tuesdays: string[30, 1],
163
+ operates_on_wednesdays: string[31, 1],
164
+ operates_on_thursdays: string[32, 1],
165
+ operates_on_fridays: string[33, 1],
166
+ operates_on_saturdays: string[34, 1],
167
+ operates_on_sundays: string[35, 1],
168
+ school_term_time: parse_value(string[36, 1]),
169
+ bank_holidays: parse_value(string[37, 1]),
170
+ route_number: parse_value(string[38, 4]),
171
+ running_board: parse_value(string[42, 6]),
172
+ vehicle_type: parse_value(string[48, 8]),
173
+ registration_number: parse_value(string[56, 8]),
174
+ route_direction: string[64, 1]
172
175
  }
173
176
  end
174
-
177
+
175
178
  def parse_value(value)
176
- return value.strip if value
179
+ value&.strip
177
180
  end
178
181
  end
179
-
180
- end
182
+ end
data/spec/atco_spec.rb CHANGED
@@ -1,150 +1,174 @@
1
- require File.dirname(__FILE__) + '/spec_helper'
1
+ # frozen_string_literal: true
2
+
3
+ require "#{File.dirname(__FILE__)}/spec_helper"
2
4
  require 'json'
3
5
 
4
6
  describe Atco do
5
-
6
7
  before(:all) do
7
-
8
8
  end
9
-
10
- it "should output file for debugging!" do
9
+
10
+ it 'should output file for debugging!' do
11
11
  result = Atco.parse('spec/fixtures/example.cif')
12
12
  File.open('test.output', 'w+') do |f|
13
13
  f.flush
14
14
  f.write(JSON.pretty_generate(result))
15
15
  end
16
- #fixture = JSON.parse(File.read('spec/fixtures/example.json'))
17
16
  end
18
-
19
- it "should parse header from fixture" do
17
+
18
+ it 'should parse header from fixture' do
20
19
  result = Atco.parse('spec/fixtures/example.cif')
21
- result[:header].should == {
22
- :file_type => "ATCO-CIF",
23
- :file_originator => "Electronic Registration",
24
- :source_product => "MIA 4.20.18",
25
- :version => "5.0",
26
- :production_datetime => "20090915113809"
20
+ expect result[:header] == {
21
+ file_type: 'ATCO-CIF',
22
+ file_originator: 'Electronic Registration',
23
+ source_product: 'MIA 4.20.18',
24
+ version: '5.0',
25
+ production_datetime: '20090915113809'
27
26
  }
28
27
  end
29
-
30
- it "should parse locations from fixture" do
28
+
29
+ it 'should parse locations from fixture' do
31
30
  result = Atco.parse('spec/fixtures/example.cif')
32
- result[:header].should == {
33
- :file_type => "ATCO-CIF",
34
- :file_originator => "Electronic Registration",
35
- :source_product => "MIA 4.20.18",
36
- :version => "5.0",
37
- :production_datetime => "20090915113809"
31
+ expect result[:header] == {
32
+ file_type: 'ATCO-CIF',
33
+ file_originator: 'Electronic Registration',
34
+ source_product: 'MIA 4.20.18',
35
+ version: '5.0',
36
+ production_datetime: '20090915113809'
38
37
  }
39
38
  end
40
-
41
- it "should parse header" do
42
- Atco.parse_header("ATCO-CIF0500Electronic Registration MIA 4.20.18 20090915113809\r\n").should == {
43
- :file_type => 'ATCO-CIF',
44
- :version => '5.0',
45
- :file_originator => 'Electronic Registration',
46
- :source_product => 'MIA 4.20.18',
47
- :production_datetime => '20090915113809'
39
+
40
+ it 'should parse header' do
41
+ expect Atco.parse_header("ATCO-CIF0500Electronic Registration MIA 4.20.18 20090915113809\r\n") == {
42
+ file_type: 'ATCO-CIF',
43
+ version: '5.0',
44
+ file_originator: 'Electronic Registration',
45
+ source_product: 'MIA 4.20.18',
46
+ production_datetime: '20090915113809'
48
47
  }
49
48
  end
50
-
51
- it "should parse bank holiday" do
52
- Atco.parse_bank_holiday("QHN20061225").should == {
53
- :record_identity => 'QH',
54
- :transaction_type => 'N',
55
- :date_of_bank_holiday => '20061225'
49
+
50
+ it 'should parse bank holiday' do
51
+ expect Atco.parse_bank_holiday('QHN20061225') == {
52
+ record_identity: 'QH',
53
+ transaction_type: 'N',
54
+ date_of_bank_holiday: '20061225'
56
55
  }
57
56
  end
58
-
59
- it "should parse operator" do
60
- Atco.parse_operator("QPNTM Translink Metro Translink Metro \r\n").should == {
61
- :record_identity => 'QP',
62
- :transaction_type => 'N',
63
- :operator => 'TM',
64
- :operator_short_form => 'Translink Metro',
65
- :operator_legal_name => 'Translink Metro'
57
+
58
+ it 'should parse operator' do
59
+ expect Atco.parse_operator("QPNTM Translink Metro Translink Metro \r\n") == {
60
+ record_identity: 'QP',
61
+ transaction_type: 'N',
62
+ operator: 'TM',
63
+ operator_short_form: 'Translink Metro',
64
+ operator_legal_name: 'Translink Metro'
66
65
  }
67
66
  end
68
-
69
- it "should parse additional location information" do
70
- Atco.parse_additional_location_info("QBN700000001252 328622 367433 \r\n").should == {
71
- :record_identity => 'QB',
72
- :transaction_type => 'N',
73
- :location => '700000001252',
74
- :grid_reference_easting => '328622',
75
- :grid_reference_northing => '367433'
67
+
68
+ it 'should parse additional location information' do
69
+ expect Atco.parse_additional_location_info("QBN700000001252 328622 367433 \r\n") == {
70
+ record_identity: 'QB',
71
+ transaction_type: 'N',
72
+ location: '700000001252',
73
+ grid_reference_easting: '328622',
74
+ grid_reference_northing: '367433'
76
75
  }
77
76
  end
78
-
79
- it "should parse location" do
80
- Atco.parse_location("QLN700000001252Conway (River Rd) 1\r\n").should == {
81
- :record_identity => 'QL',
82
- :transaction_type => 'N',
83
- :location => '700000001252',
84
- :full_location => 'Conway (River Rd)',
85
- :gazetteer_code => '1'
77
+
78
+ it 'should parse location' do
79
+ expect Atco.parse_location("QLN700000001252Conway (River Rd) 1\r\n") == {
80
+ record_identity: 'QL',
81
+ transaction_type: 'N',
82
+ location: '700000001252',
83
+ full_location: 'Conway (River Rd)',
84
+ gazetteer_code: '1'
86
85
  }
87
86
  end
88
87
 
89
88
  # QT7000000012520605 T1F0
90
- it "should parse destination" do
91
- Atco.parse_destination("QT7000000012520605 T1F0\r\n").should == {
92
- :record_identity => 'QT',
93
- :location => '700000001252',
94
- :published_arrival_time => '0605',
95
- :bay_number => "",
96
- :timing_point_indicator => 'T1',
97
- :fare_stage_indicator => 'F0'
89
+ it 'should parse destination' do
90
+ expect Atco.parse_destination("QT7000000012520605 T1F0\r\n") == {
91
+ record_identity: 'QT',
92
+ location: '700000001252',
93
+ published_arrival_time: '0605',
94
+ bay_number: '',
95
+ timing_point_indicator: 'T1',
96
+ fare_stage_indicator: 'F0'
98
97
  }
99
98
  end
100
-
101
- it "should parse intermediate" do
102
- Atco.parse_intermediate("QI70000000125607120712B T1F0\r\n").should == {
103
- :record_identity => 'QI',
104
- :location => '700000001256',
105
- :published_arrival_time => '0712',
106
- :published_departure_time => '0712',
107
- :activity_flag => "B",
108
- :bay_number => "",
109
- :timing_point_indicator => 'T1',
110
- :fare_stage_indicator => 'F0'
99
+
100
+ it 'should parse intermediate' do
101
+ expect Atco.parse_intermediate("QI70000000125607120712B T1F0\r\n") == {
102
+ record_identity: 'QI',
103
+ location: '700000001256',
104
+ published_arrival_time: '0712',
105
+ published_departure_time: '0712',
106
+ activity_flag: 'B',
107
+ bay_number: '',
108
+ timing_point_indicator: 'T1',
109
+ fare_stage_indicator: 'F0'
111
110
  }
112
111
  end
113
-
114
- it "should parse origin" do
115
- Atco.parse_origin("QO7000000012520730 T1F0\r\n").should == {
116
- :record_identity => 'QO',
117
- :location => '700000001252',
118
- :published_departure_time => '0730',
119
- :bay_number => "",
120
- :timing_point_indicator => 'T1',
121
- :fare_stage_indicator => 'F0'
112
+
113
+ it 'should parse origin' do
114
+ expect Atco.parse_origin("QO7000000012520730 T1F0\r\n") == {
115
+ record_identity: 'QO',
116
+ location: '700000001252',
117
+ published_departure_time: '0730',
118
+ bay_number: '',
119
+ timing_point_indicator: 'T1',
120
+ fare_stage_indicator: 'F0'
122
121
  }
123
122
  end
124
123
 
125
- it "should parse journey header" do
126
- Atco.parse_journey_header("QSNTM 13986520091005 1111100 9A 9018 0 I\r\n").should == {
127
- :record_identity => 'QS',
128
- :transaction_type => 'N',
129
- :operator => 'TM',
130
- :unique_journey_identifier => '139865',
131
- :first_date_of_operation => '20091005',
132
- :last_date_of_operation => '',
133
- :operates_on_mondays => '1',
134
- :operates_on_tuesdays => '1',
135
- :operates_on_wednesdays => '1',
136
- :operates_on_thursdays => '1',
137
- :operates_on_fridays => '1',
138
- :operates_on_saturdays => '0',
139
- :operates_on_sundays => '0',
140
- :school_term_time => '',
141
- :bank_holidays => '',
142
- :route_number => '9A',
143
- :running_board => '9018',
144
- :vehicle_type => '0',
145
- :registration_number => '',
146
- :route_direction => 'I'
124
+ it 'should parse journey header' do
125
+ expect Atco.parse_journey_header("QSNTM 13986520091005 1111100 9A 9018 0 I\r\n") == {
126
+ record_identity: 'QS',
127
+ transaction_type: 'N',
128
+ operator: 'TM',
129
+ unique_journey_identifier: '139865',
130
+ first_date_of_operation: '20091005',
131
+ last_date_of_operation: '',
132
+ operates_on_mondays: '1',
133
+ operates_on_tuesdays: '1',
134
+ operates_on_wednesdays: '1',
135
+ operates_on_thursdays: '1',
136
+ operates_on_fridays: '1',
137
+ operates_on_saturdays: '0',
138
+ operates_on_sundays: '0',
139
+ school_term_time: '',
140
+ bank_holidays: '',
141
+ route_number: '9A',
142
+ running_board: '9018',
143
+ vehicle_type: '0',
144
+ registration_number: '',
145
+ route_direction: 'I'
147
146
  }
148
147
  end
149
148
 
150
- end
149
+ describe 'with example.cif' do
150
+ before(:all) do
151
+ @atco = Atco.parse('spec/fixtures/example.cif')
152
+ end
153
+
154
+ it 'should parse 1 journey' do
155
+ expect @atco[:journeys].size == 1
156
+ end
157
+
158
+ it 'should parse journeys into Atco::Joruney objects' do
159
+ expect(@atco[:journeys]['139748']).to be_a_kind_of(Atco::Journey)
160
+ end
161
+
162
+ it 'should parse 6 stops for joureny 139748' do
163
+ expect @atco[:journeys]['139748'].stops.size == 6
164
+ end
165
+
166
+ it 'should parse 6 stops for joureny 139748' do
167
+ expect @atco[:journeys]['139748'].stops.size == 6
168
+ end
169
+
170
+ it 'should parse 2 locations' do
171
+ expect @atco[:locations].size == 2
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,30 @@
1
+ ATCO-CIF0500Electronic Registration MIA 4.20.18 20090915113809
2
+ QLN700000001433Donegal Square East 1
3
+ QBN700000001433 333935 373979
4
+ GS00001433 N Belfast Metro Ops 7000
5
+ GR00001433Donegall Square East 7000
6
+ QLN700000001627Great Northern Mall 1
7
+ QBN700000001627 333575 373717
8
+ GS00001627 N Belfast Metro Ops 7000
9
+ GR00001627Great Victoria Street 7000 7000
10
+ QPNTM Translink Metro Translink Metro
11
+ QQ
12
+ ZLTMAO009AT05O
13
+ ZD20091005 Monday to Friday FFFFF00
14
+ ZSTMAO009A9A City Centre - Conway
15
+ ZAN700000001433 P1W1T1
16
+ ZAN700000001627 P1W1T1
17
+ QSNTM 13974820091005 1111100 9A 9011 0 O
18
+ ZJTMAO009A004 1 370 000CB 545 2237 C FFFFF00L0
19
+ QO7000000014330545 T1F0
20
+ ZECH0 054500054500P0W0
21
+ QI70000000162705460546B T1F0
22
+ ZECH0 054600054600P0W0
23
+ QI70000000124806020602B T1F0
24
+ ZECH0 060200060200P0W0
25
+ QI70000000125006030603B T0F0
26
+ ZECH0 060348060348P0W0
27
+ QT7000000012520605 T1F0
28
+ ZECH0 060500060500P0W0
29
+ QVN0 Bus
30
+ QHN20071226
@@ -0,0 +1,98 @@
1
+ {
2
+ "header": {
3
+ "file_type": "ATCO-CIF",
4
+ "file_originator": "Electronic Registration",
5
+ "source_product": "MIA 4.20.18",
6
+ "version": "5.0",
7
+ "production_datetime": "20090915113809"
8
+ },
9
+ "locations": [
10
+ [
11
+ {
12
+ "record_identity": "QL",
13
+ "location": "700000001433",
14
+ "transaction_type": "N",
15
+ "full_location": "Donegal Square East",
16
+ "gazetteer_code": "1"
17
+ },
18
+ {
19
+ "record_identity": "QB",
20
+ "location": "700000001433",
21
+ "transaction_type": "N",
22
+ "grid_reference_easting": "333935",
23
+ "grid_reference_northing": "373979"
24
+ }
25
+ ],
26
+ [
27
+ {
28
+ "record_identity": "QL",
29
+ "location": "700000001627",
30
+ "transaction_type": "N",
31
+ "full_location": "Great Northern Mall",
32
+ "gazetteer_code": "1"
33
+ },
34
+ {
35
+ "record_identity": "QB",
36
+ "location": "700000001627",
37
+ "transaction_type": "N",
38
+ "grid_reference_easting": "333575",
39
+ "grid_reference_northing": "373717"
40
+ }
41
+ ]
42
+ ],
43
+ "journeys": {
44
+ "139748": [
45
+ {
46
+ "record_identity": "QO",
47
+ "published_departure_time": "0545",
48
+ "location": "700000001433",
49
+ "bay_number": "",
50
+ "timing_point_indicator": "T1",
51
+ "fare_stage_indicator": "F0"
52
+ },
53
+ {
54
+ "record_identity": "QI",
55
+ "published_departure_time": "0546",
56
+ "location": "700000001627",
57
+ "published_arrival_time": "0546",
58
+ "activity_flag": "B",
59
+ "bay_number": "",
60
+ "timing_point_indicator": "T1",
61
+ "fare_stage_indicator": "F0"
62
+ },
63
+ {
64
+ "record_identity": "QI",
65
+ "published_departure_time": "0602",
66
+ "location": "700000001248",
67
+ "published_arrival_time": "0602",
68
+ "activity_flag": "B",
69
+ "bay_number": "",
70
+ "timing_point_indicator": "T1",
71
+ "fare_stage_indicator": "F0"
72
+ },
73
+ {
74
+ "record_identity": "QI",
75
+ "published_departure_time": "0603",
76
+ "location": "700000001250",
77
+ "published_arrival_time": "0603",
78
+ "activity_flag": "B",
79
+ "bay_number": "",
80
+ "timing_point_indicator": "T0",
81
+ "fare_stage_indicator": "F0"
82
+ },
83
+ {
84
+ "record_identity": "QT",
85
+ "location": "700000001252",
86
+ "published_arrival_time": "0605",
87
+ "bay_number": "",
88
+ "timing_point_indicator": "T1",
89
+ "fare_stage_indicator": "F0"
90
+ },
91
+ {
92
+ "record_identity": "QH",
93
+ "transaction_type": "N",
94
+ "date_of_bank_holiday": "20071226"
95
+ }
96
+ ]
97
+ }
98
+ }
data/spec/spec_helper.rb CHANGED
@@ -1,2 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rubygems'
2
- require File.dirname(__FILE__) + '/../lib/atco'
4
+ require 'rspec'
5
+
6
+ require "#{File.dirname(__FILE__)}/../lib/atco"
metadata CHANGED
@@ -1,67 +1,84 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: atco
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 0
8
- - 1
9
- version: 0.0.1
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
10
5
  platform: ruby
11
- authors:
6
+ authors:
12
7
  - David Rice
13
8
  autorequire:
14
9
  bindir: bin
15
10
  cert_chain: []
16
-
17
- date: 2010-02-22 00:00:00 +00:00
18
- default_executable:
19
- dependencies: []
20
-
21
- description: Simple and opinionated library for parsing ATCO-CIF files with Ruby.
11
+ date: 2024-04-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Simple and opinionated library for parsing ATCO .cif files to JSON with
42
+ Ruby
22
43
  email: me@davidjrice.co.uk
23
44
  executables: []
24
-
25
45
  extensions: []
26
-
27
- extra_rdoc_files:
28
- - README.mdown
29
- files:
30
- - README.mdown
46
+ extra_rdoc_files:
47
+ - README.md
48
+ files:
49
+ - README.md
31
50
  - Rakefile
32
51
  - VERSION
33
52
  - lib/atco.rb
34
- - lib/location.rb
35
- has_rdoc: true
53
+ - lib/atco/journey.rb
54
+ - lib/atco/location.rb
55
+ - lib/atco/stop.rb
56
+ - spec/atco_spec.rb
57
+ - spec/fixtures/example.cif
58
+ - spec/fixtures/example.json
59
+ - spec/spec_helper.rb
36
60
  homepage: http://github.com/davidjrice/atco
37
- licenses: []
38
-
61
+ licenses:
62
+ - MIT
63
+ metadata: {}
39
64
  post_install_message:
40
- rdoc_options:
41
- - --charset=UTF-8
42
- require_paths:
65
+ rdoc_options:
66
+ - "--charset=UTF-8"
67
+ require_paths:
43
68
  - lib
44
- required_ruby_version: !ruby/object:Gem::Requirement
45
- requirements:
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ requirements:
46
71
  - - ">="
47
- - !ruby/object:Gem::Version
48
- segments:
49
- - 0
50
- version: "0"
51
- required_rubygems_version: !ruby/object:Gem::Requirement
52
- requirements:
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
53
76
  - - ">="
54
- - !ruby/object:Gem::Version
55
- segments:
56
- - 0
57
- version: "0"
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
58
79
  requirements: []
59
-
60
- rubyforge_project:
61
- rubygems_version: 1.3.6
80
+ rubygems_version: 3.5.3
62
81
  signing_key:
63
- specification_version: 3
64
- summary: Simple and opinionated library for parsing ATCO-CIF files with Ruby.
65
- test_files:
66
- - spec/atco_spec.rb
67
- - spec/spec_helper.rb
82
+ specification_version: 4
83
+ summary: Parse ATCO .cif files to JSON with Ruby
84
+ test_files: []
data/lib/location.rb DELETED
@@ -1,23 +0,0 @@
1
- class Location
2
-
3
- attr_accessor :name, :identifier, :easting, :northing, :gazeteer_code
4
-
5
- def initialize(location_header, additional_location_information)
6
- @name = location_header[:full_location]
7
- @identifier = location_header[:record_identity]
8
- @easting = additional_location_information[:grid_reference_easting]
9
- @northing = additional_location_information[:grid_reference_northing]
10
- @gazeteer_code = location_header[:gazetteer_code]
11
- end
12
-
13
- def to_json(*a)
14
- {
15
- :name => @name,
16
- :identifier => @identifier,
17
- :easting => @easting,
18
- :northing => @northing,
19
- :gazeteer_code => @gazeteer_code
20
- }.to_json(*a)
21
- end
22
-
23
- end