Class: Identifiers::ISBN

Inherits:
Object
  • Object
show all
Defined in:
lib/identifiers/isbn.rb

Constant Summary collapse

REGEX_13 =
/\b97[89]\d{10}\b/
REGEX_10 =
/\b\d{9}(?:\d|X)\b/
REGEX_A =
%r{\b(?<=10\.)97[89]\.\d{2,8}/\d{1,7}\b}

Class Method Summary collapse

Class Method Details

.extract(str) ⇒ Object



7
8
9
# File 'lib/identifiers/isbn.rb', line 7

def self.extract(str)
  extract_isbn_as(str) + extract_thirteen_digit_isbns(str) + extract_ten_digit_isbns(str)
end

.extract_isbn_as(str) ⇒ Object



11
12
13
# File 'lib/identifiers/isbn.rb', line 11

def self.extract_isbn_as(str)
  extract_thirteen_digit_isbns(str.scan(REGEX_A).join("\n").tr('/.', ''))
end

.extract_ten_digit_isbns(str) ⇒ Object



19
20
21
22
23
24
25
26
27
# File 'lib/identifiers/isbn.rb', line 19

def self.extract_ten_digit_isbns(str)
  str.gsub(/(?<=\d)[- ](?=[\dX])/i, '').scan(REGEX_10).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) ⇒ Object



15
16
17
# File 'lib/identifiers/isbn.rb', line 15

def self.extract_thirteen_digit_isbns(str)
  str.gsub(/(?<=\d)[- ](?=\d)/, '').scan(REGEX_13).select { |isbn| valid_isbn_13?(isbn) }
end

.isbn_13_check_digit(isbn) ⇒ Object



29
30
31
32
33
34
35
36
37
38
# File 'lib/identifiers/isbn.rb', line 29

def self.isbn_13_check_digit(isbn)
  sum = isbn.each_char.zip([1, 3].cycle).reduce(0) { |sum, values| sum + (Integer(values[0]) * values[1]) }
  check_digit = 10 - (sum % 10)

  if check_digit == 10
    0
  else
    check_digit
  end
end

.valid_isbn_10?(isbn) ⇒ Boolean

Returns:

  • (Boolean)


48
49
50
51
52
53
54
55
56
# File 'lib/identifiers/isbn.rb', line 48

def self.valid_isbn_10?(isbn)
  return false unless isbn =~ REGEX_10

  result = isbn.each_char.with_index.reduce(0) { |sum, values|
    sum + (Integer(values[0].sub('X', '10')) * values[1].succ)
  }

  (result % 11).zero?
end

.valid_isbn_13?(isbn) ⇒ Boolean

Returns:

  • (Boolean)


40
41
42
43
44
45
46
# File 'lib/identifiers/isbn.rb', line 40

def self.valid_isbn_13?(isbn)
  return false unless isbn =~ REGEX_13

  result = isbn.each_char.zip([1, 3].cycle).reduce(0) { |sum, values| sum + (Integer(values[0]) * values[1]) }

  (result % 10).zero?
end