Sha256: df78298c9cdfc6fa66ef06fed0e80273f44f8409e76ef176058c2f55afaa7a32

Contents?: true

Size: 1.24 KB

Versions: 1

Compression:

Stored size: 1.24 KB

Contents

# frozen_string_literal: true

require 'set'

module SecId
  class FIGI < Base
    ID_REGEX = /\A
      (?<identifier>
        (?<prefix>[B-DF-HJ-NP-TV-Z0-9]{2})
        G
        (?<random_part>[B-DF-HJ-NP-TV-Z0-9]{8}))
      (?<check_digit>\d)?
    \z/x

    RESTRICTED_PREFIXES = Set.new %w[BS BM GG GB GH KY VG]

    attr_reader :prefix, :random_part

    def initialize(figi)
      figi_parts = parse figi
      @identifier = figi_parts[:identifier]
      @prefix = figi_parts[:prefix]
      @random_part = figi_parts[:random_part]
      @check_digit = figi_parts[:check_digit]&.to_i
    end

    def valid_format?
      !identifier.nil? && !RESTRICTED_PREFIXES.include?(prefix)
    end

    def calculate_check_digit
      unless valid_format?
        raise InvalidFormatError, "FIGI '#{full_number}' is invalid and check-digit cannot be calculated!"
      end

      mod10(modified_luhn_sum)
    end

    private

    # https://en.wikipedia.org/wiki/Luhn_algorithm
    def modified_luhn_sum
      reversed_id_digits.each_with_index.reduce(0) do |sum, (digit, index)|
        digit *= 2 if index.odd?
        sum + digit.divmod(10).sum
      end
    end

    def reversed_id_digits
      identifier.each_char.map(&method(:char_to_digit)).reverse!
    end
  end
end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
sec_id-4.1.0 lib/sec_id/figi.rb