Sha256: 95f3d2a47833d7b4c7cb093937d7a2c69737eb42b2a7a1e6818db7d3a44920a6

Contents?: true

Size: 1.15 KB

Versions: 1

Compression:

Stored size: 1.15 KB

Contents

# frozen_string_literal: true

module SecId
  # https://en.wikipedia.org/wiki/International_Securities_Identification_Number
  class ISIN < Base
    ID_REGEX = /\A
      (?<identifier>
        (?<country_code>[A-Z]{2})
        (?<nsin>[A-Z0-9]{9}))
      (?<check_digit>\d)?
    \z/x.freeze

    attr_reader :country_code, :nsin

    def initialize(isin)
      isin_parts = parse isin
      @identifier = isin_parts[:identifier]
      @country_code = isin_parts[:country_code]
      @nsin = isin_parts[:nsin]
      @check_digit = isin_parts[:check_digit]&.to_i
    end

    def calculate_check_digit
      return mod_10(luhn_sum) if valid_format?

      raise InvalidFormatError, "ISIN '#{full_number}' is invalid and check-digit cannot be calculated!"
    end

    private

    # https://en.wikipedia.org/wiki/Luhn_algorithm
    def luhn_sum
      sum = 0

      id_digits.reverse.each_slice(2) do |even, odd|
        double_even = (even || 0) * 2
        double_even -= 9 if double_even > 9
        sum += double_even + (odd || 0)
      end

      sum
    end

    def id_digits
      @id_digits ||= identifier.each_char.flat_map(&method(:char_to_digits))
    end
  end
end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
sec_id-3.0.0 lib/sec_id/isin.rb