class Identifiers::ISBN

Constants

ISBN_10_REGEXP
ISBN_13_REGEXP
ISBN_A_REGEXP

Public Class Methods

digits_of(isbn) click to toggle source
# File lib/identifiers/isbn.rb, line 103
def self.digits_of(isbn)
  isbn.to_s.each_char.map { |char| char == 'X' ? 10 : Integer(char) }.to_enum
end
extract(str) click to toggle source
# File lib/identifiers/isbn.rb, line 43
def self.extract(str)
  extract_isbn_as(str) + extract_thirteen_digit_isbns(str) + extract_ten_digit_isbns(str)
end
extract_isbn_as(str) click to toggle source
# File lib/identifiers/isbn.rb, line 47
def self.extract_isbn_as(str)
  extract_thirteen_digit_isbns(str.to_s.scan(ISBN_A_REGEXP).join("\n").tr('/.', ''))
end
extract_ten_digit_isbns(str) click to toggle source
# File lib/identifiers/isbn.rb, line 60
def self.extract_ten_digit_isbns(str)
  str
    .to_s
    .scan(ISBN_10_REGEXP)
    .select { |isbn, hyphen| !hyphen || isbn.count(hyphen) == 3 }
    .map { |isbn, hyphen| isbn.delete(hyphen.to_s) }
    .select { |isbn| valid_isbn_10?(isbn) }
    .map { |isbn|
      isbn.chop!
      isbn.prepend('978')
      isbn << isbn_13_check_digit(isbn).to_s

      isbn
    }
end
extract_thirteen_digit_isbns(str) click to toggle source
# File lib/identifiers/isbn.rb, line 51
def self.extract_thirteen_digit_isbns(str)
  str
    .to_s
    .scan(ISBN_13_REGEXP)
    .select { |isbn, hyphen| !hyphen || isbn.count(hyphen) == 4 }
    .map { |isbn, hyphen| isbn.delete(hyphen.to_s) }
    .select { |isbn| valid_isbn_13?(isbn) }
end
isbn_13_check_digit(isbn) click to toggle source
# File lib/identifiers/isbn.rb, line 76
def self.isbn_13_check_digit(isbn)
  sum = digits_of(isbn).zip([1, 3].cycle).map { |digit, weight| digit * weight }.reduce(:+)
  check_digit = 10 - (sum % 10)

  if check_digit == 10
    0
  else
    check_digit
  end
end
valid_isbn_10?(isbn) click to toggle source
# File lib/identifiers/isbn.rb, line 95
def self.valid_isbn_10?(isbn)
  return false unless String(isbn).length == 10 && isbn =~ ISBN_10_REGEXP

  result = digits_of(isbn).with_index.map { |digit, weight| digit * weight.succ }.reduce(:+)

  (result % 11).zero?
end
valid_isbn_13?(isbn) click to toggle source
# File lib/identifiers/isbn.rb, line 87
def self.valid_isbn_13?(isbn)
  return false unless String(isbn).length == 13 && isbn =~ ISBN_13_REGEXP

  result = digits_of(isbn).zip([1, 3].cycle).map { |digit, weight| digit * weight }.reduce(:+)

  (result % 10).zero?
end