# frozen_string_literal: true require 'japan_etc/entrance_or_exit' require 'japan_etc/error' require 'japan_etc/road' require 'japan_etc/direction' require 'japan_etc/util' module JapanETC class Tollbooth include Util attr_accessor :identifier, :road, :name, :entrance_or_exit, :direction, :notes def self.create( road_number:, tollbooth_number:, road_name:, route_name: nil, name:, direction: nil, entrance_or_exit: nil, note: nil ) identifier = Identifier.new(road_number, tollbooth_number) road = Road.new(road_name, route_name) new(identifier, road, name, direction, entrance_or_exit, note) end def initialize(identifier, road, name, direction = nil, entrance_or_exit = nil, note = nil) # rubocop:disable Metrics/LineLength raise ValidationError if identifier.nil? || road.nil? || name.nil? @identifier = identifier @road = road @name = normalize(name) @direction = direction @entrance_or_exit = entrance_or_exit @notes = [] notes << normalize(note) if note extract_notes_from_name! extract_direction_from_notes! extract_entrance_or_exit_from_notes! extract_direction_from_name! extract_entrance_or_exit_from_name! end def initialize_copy(original) @road = original.road.dup @name = original.name.dup end def ==(other) other.is_a?(self.class) && identifier == other.identifier end alias eql? == def hash identifier.hash end def to_a [ identifier.to_a, road.to_a, name, direction, entrance_or_exit, notes.empty? ? nil : notes.join(' ') ].flatten end def extract_notes_from_name! name.sub!(/(?.+?)?\s*[(\(](?.+?)[)\)]\s*(?.+)?/) do match = Regexp.last_match if match[:head] prepend_to_notes(match[:tail]) if match[:tail] prepend_to_notes(match[:note]) match[:head] elsif match[:tail] prepend_to_notes(match[:note]) match[:tail] else match[:note] end end name.sub!(/第[一二三]\z/) do |match| prepend_to_notes(match) '' end end def extract_direction_from_notes! notes.reject! do |note| found_direction = Direction.from(note) next false unless found_direction if direction raise ValidationError unless found_direction == direction else @direction = found_direction end true end end def extract_entrance_or_exit_from_notes! notes.reject! do |note| found_entrance_or_exit = EntranceOrExit.from(note) next false unless found_entrance_or_exit if entrance_or_exit raise ValidationError unless found_entrance_or_exit == entrance_or_exit else @entrance_or_exit = found_entrance_or_exit end true end end def extract_direction_from_name! name.sub!(/(?:上り|下り|[東西南北]行き?)/) do |match| found_direction = Direction.from(match) if direction found_direction == direction ? '' : match else @direction = found_direction '' end end end def extract_entrance_or_exit_from_name! name.sub!(/(?:入口|出口|料金所)/) do |match| found_entrance_or_exit = EntranceOrExit.from(match) found_entrance_or_exit ||= EntranceOrExit::EXIT if entrance_or_exit found_entrance_or_exit == entrance_or_exit ? '' : match else @entrance_or_exit = found_entrance_or_exit '' end end end def prepend_to_notes(note) note = normalize(note) notes.prepend(note) end Identifier = Struct.new(:road_number, :tollbooth_number) do include Util def initialize(road_number, tollbooth_number) road_number = convert_to_integer(road_number) raise ValidationError, '#road_number cannot be nil' if road_number.nil? tollbooth_number = convert_to_integer(tollbooth_number) raise ValidationError, '#tollbooth_number cannot be nil' if tollbooth_number.nil? super(road_number, tollbooth_number) end end end end