diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 44e75a4..c95a62d 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -2,4 +2,5 @@ * David Rice [@davidjrice](https://github.com/davidjrice) * Thomas Buckley-Houston [@tombh](https://github.com/tombh) -* Martin Sidaway [@martinjos](https://github.com/martinjos) \ No newline at end of file +* Martin Sidaway [@martinjos](https://github.com/martinjos) +* Ian Dunlop [@ianwdunlop](https://github.com/ianwdunlop) diff --git a/Gemfile.lock b/Gemfile.lock index 2164484..957b3bb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - atco (1.0.7) + atco (1.0.8) GEM remote: https://rubygems.org/ diff --git a/lib/atco.rb b/lib/atco.rb index dcec975..52d6678 100644 --- a/lib/atco.rb +++ b/lib/atco.rb @@ -2,6 +2,7 @@ require "open3" require "tempfile" +require_relative "atco/header" require_relative "atco/location" require_relative "atco/journey" require_relative "atco/stop" @@ -39,7 +40,7 @@ def parse(file) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, data.each_with_index do |line, line_number| # rubocop:disable Metrics/BlockLength if line_number.zero? - header = parse_header(line) + header = Header.parse(line) next end @@ -78,16 +79,6 @@ def parse(file) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, { header: header, locations: locations, journeys: journeys, unparsed: unparsed } end - def parse_header(string) - { - file_type: string[0, 8], - version: "#{string[8, 2].to_i}.#{string[10, 2].to_i}", - file_originator: string[12, 32].strip!, - source_product: string[44, 16].strip!, - production_datetime: string[60, 14] - } - end - def parse_bank_holiday(string) { record_identity: string[0, 2], diff --git a/lib/atco/header.rb b/lib/atco/header.rb new file mode 100644 index 0000000..7484f7c --- /dev/null +++ b/lib/atco/header.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module Atco + # Atco::Header is a class to abstract ATCO-CIF Header data. + class Header + attr_accessor :file_type, + :version, + :file_originator, + :source_product, + :production_datetime + + # Public: Parse a header line from an ATCO-CIF file. + # EXAMPLE: + # "ATCO-CIF0500Electronic Registration MIA 4.20.18 20090915113809\r\n" + def self.parse(line) + data = { + file_type: line[0, 8], + version: "#{line[8, 2].to_i}.#{line[10, 2].to_i}", + file_originator: line[12, 32].strip!, + source_product: line[44, 16].strip!, + production_datetime: line[60, 14] + } + new(data) + end + + def initialize(data) + @file_type = data[:file_type] + @version = data[:version] + @file_originator = data[:file_originator] + @source_product = data[:source_product] + @production_datetime = data[:production_datetime] + end + + def attributes + { + file_type: @file_type, + version: @version, + file_originator: @file_originator, + source_product: @source_product, + production_datetime: @production_datetime + } + end + + def to_json(*attrs) + attributes.to_json(*attrs) + end + end +end diff --git a/lib/atco/version.rb b/lib/atco/version.rb index c703328..0d7c324 100644 --- a/lib/atco/version.rb +++ b/lib/atco/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Atco - VERSION = "1.0.7" + VERSION = "1.0.8" end diff --git a/spec/atco_spec.rb b/spec/atco_spec.rb index 5755037..209cd48 100644 --- a/spec/atco_spec.rb +++ b/spec/atco_spec.rb @@ -7,44 +7,6 @@ expect(Atco::VERSION).not_to be nil end - it "should parse header from fixture" do - result = Atco.parse("spec/fixtures/example.cif") - expect(result[:header]).to eq( - { - file_type: "ATCO-CIF", - file_originator: "Electronic Registration", - source_product: "MIA 4.20.18", - version: "5.0", - production_datetime: "20090915113809" - } - ) - end - - it "should parse locations from fixture" do - result = Atco.parse("spec/fixtures/example.cif") - expect(result[:header]).to eq( - { - file_type: "ATCO-CIF", - file_originator: "Electronic Registration", - source_product: "MIA 4.20.18", - version: "5.0", - production_datetime: "20090915113809" - } - ) - end - - it "should parse header" do - expect(Atco.parse_header("ATCO-CIF0500Electronic Registration MIA 4.20.18 20090915113809\r\n")).to eq( - { - file_type: "ATCO-CIF", - version: "5.0", - file_originator: "Electronic Registration", - source_product: "MIA 4.20.18", - production_datetime: "20090915113809" - } - ) - end - it "should parse bank holiday" do expect(Atco.parse_bank_holiday("QHN20061225")).to eq( { @@ -159,62 +121,4 @@ } ) end - - describe "with example.cif" do # rubocop:disable Metrics/BlockLength - before(:all) do - @atco = Atco.parse("spec/fixtures/example.cif") - end - - it "should parse 1 journey" do - expect(@atco[:journeys].size).to eq(1) - end - - it "should parse journeys into Atco::Joruney objects" do - expect(@atco[:journeys]["139748"]).to be_a_kind_of(Atco::Journey) - end - - it "should parse 6 stops for journey 139748" do - expect(@atco[:journeys]["139748"].stops.size).to eq(6) - end - - it "should parse 2 locations" do - expect(@atco[:locations].size).to eq(2) - end - - it "should output file as JSON" do - output = File.join(File.dirname(__FILE__), "artefacts", "test.json") - File.open(output, "w+") do |f| - f.flush - f.write(JSON.pretty_generate(@atco)) - end - - expect(File.exist?(output)).to be true - - data = File.read(output) - json = JSON.parse(data) - expect(json).to be_a(Hash) - end - - it "should return 17 unparsed lines" do - expect(@atco[:unparsed].size).to eq(17) - end - - it "should not parse GS records" do - expect(@atco[:unparsed][0]).to eq( - { - line: "GS00001433 N Belfast Metro Ops 7000\n", - line_number: 3 - } - ) - end - - it "should not parse GR records" do - expect(@atco[:unparsed][1]).to eq( - { - line: "GR00001433Donegall Square East 7000\n", # rubocop:disable Layout/LineLength - line_number: 4 - } - ) - end - end end diff --git a/spec/fixtures/example.cif b/spec/fixtures/translink-example.cif similarity index 100% rename from spec/fixtures/example.cif rename to spec/fixtures/translink-example.cif diff --git a/spec/integration/translink_spec.rb b/spec/integration/translink_spec.rb new file mode 100644 index 0000000..2248d58 --- /dev/null +++ b/spec/integration/translink_spec.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +RSpec.describe "with example.cif" do # rubocop:disable Metrics/BlockLength + before(:all) do + @atco = Atco.parse("spec/fixtures/translink-example.cif") + end + + it "should parse header from fixture" do + expect(@atco[:header].attributes).to eq( + { + file_type: "ATCO-CIF", + file_originator: "Electronic Registration", + source_product: "MIA 4.20.18", + version: "5.0", + production_datetime: "20090915113809" + } + ) + end + + it "should parse 1 journey" do + expect(@atco[:journeys].size).to eq(1) + end + + it "should parse journeys into Atco::Joruney objects" do + expect(@atco[:journeys]["139748"]).to be_a_kind_of(Atco::Journey) + end + + it "should parse 6 stops for journey 139748" do + expect(@atco[:journeys]["139748"].stops.size).to eq(6) + end + + it "should parse 2 locations" do + expect(@atco[:locations].size).to eq(2) + end + + it "should output file as JSON" do + output = File.join(File.dirname(__FILE__), "..", "artefacts", "test.json") + File.open(output, "w+") do |f| + f.flush + f.write(JSON.pretty_generate(@atco)) + end + + expect(File.exist?(output)).to be true + + data = File.read(output) + json = JSON.parse(data) + expect(json).to be_a(Hash) + end + + it "should return 17 unparsed lines" do + expect(@atco[:unparsed].size).to eq(17) + end + + it "should not parse GS records" do + expect(@atco[:unparsed][0]).to eq( + { + line: "GS00001433 N Belfast Metro Ops 7000\n", + line_number: 3 + } + ) + end + + it "should not parse GR records" do + expect(@atco[:unparsed][1]).to eq( + { + line: "GR00001433Donegall Square East 7000\n", # rubocop:disable Layout/LineLength + line_number: 4 + } + ) + end +end diff --git a/spec/unit/header_spec.rb b/spec/unit/header_spec.rb new file mode 100644 index 0000000..61380f7 --- /dev/null +++ b/spec/unit/header_spec.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +RSpec.describe Atco::Header do + before(:all) do + line = "ATCO-CIF0500Electronic Registration MIA 4.20.18 20090915113809\r\n" + @header = Atco::Header.parse(line) + end + + it "should be a Header object" do + expect(@header).to be_a_kind_of(Atco::Header) + end + + it "should parse header to attributes" do + expect(@header.attributes).to eq( + { + file_type: "ATCO-CIF", + version: "5.0", + file_originator: "Electronic Registration", + source_product: "MIA 4.20.18", + production_datetime: "20090915113809" + } + ) + end + + it "should parse header to json" do + expect(@header.to_json).to eq( + "{\"file_type\":\"ATCO-CIF\",\"version\":\"5.0\",\"file_originator\":\"Electronic Registration\",\"source_product\":\"MIA 4.20.18\",\"production_datetime\":\"20090915113809\"}" # rubocop:disable Metrics/LineLength + ) + end +end