Module: StdNum::ISBN

Extended by:
Helpers
Defined in:
lib/library_stdnums.rb

Overview

Validate, convert, and normalize ISBNs (10-digit or 13-digit)

Constant Summary

Constants included from Helpers

Helpers::STDNUMPAT

Class Method Summary (collapse)

Methods included from Helpers

extractNumber, reduce_to_basics

Class Method Details

+ (Array<String,String>?) allNormalizedValues(isbn)

Return an array of the ISBN13 and ISBN10 (in that order) for the passed in value. You'll only get one value back if it's a 13-digit ISBN that can't be converted to an ISBN10. it can't be recognized.

Examples:

Get the normalized values and index them (if valid) or original value (if not)

norms = StdNum::ISBN.allNormalizedValues(rawisbn)
doc['isbn'] = norms ? norms : [rawisbn]

Parameters:

  • isbn (String)

    The original ISBN, in 10-character or 13-digit format

Returns:

  • (Array<String,String>, nil)

    Either the (one or two) normalized ISBNs, or nil if



151
152
153
154
155
156
157
158
159
160
# File 'lib/library_stdnums.rb', line 151

def self.allNormalizedValues isbn
  isbn = reduce_to_basics isbn, [10,13]
  return [] unless isbn
  case isbn.size
  when 10
    return [self.convert_to_13(isbn), isbn]
  when 13
    return [isbn, self.convert_to_10(isbn)].compact
  end
end

+ (String?) checkdigit(isbn, preprocessed = false)

Compute check digits for 10 or 13-digit ISBNs. See algorithm at en.wikipedia.org/wiki/International_Standard_Book_Number

Parameters:

  • isbn (String)

    The ISBN (we'll try to clean it up if possible)

  • preprocessed (Boolean) (defaults to: false)

    Set to true if the ISBN has already been through reduce_to_basics

Returns:

  • (String, nil)

    the one-character checkdigit, or nil if it's not an ISBN string



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/library_stdnums.rb', line 57

def self.checkdigit isbn, preprocessed = false
  isbn = reduce_to_basics isbn, [10,13] unless preprocessed
  return nil unless isbn

  checkdigit = 0
  if isbn.size == 10
    digits = isbn[0..8].split(//).map {|i| i.to_i}
    (1..9).each do |i|
      checkdigit += digits[i-1] * i
    end
    checkdigit = checkdigit % 11
    return 'X' if checkdigit == 10
    return checkdigit.to_s
  else # size == 13
    checkdigit = 0
    digits = isbn[0..11].split(//).map {|i| i.to_i}
    6.times do
      checkdigit += digits.shift
      checkdigit += digits.shift * 3
    end
    check = 10 - (checkdigit % 10)
    check = 0 if check == 10
    return check.to_s
  end
end

+ (String) convert_to_10(isbn)

Convert to 10 if it's 13 digits and the first three digits are 978. Pass through anything 10-digits, and return nil for everything else.

Parameters:

  • isbn (String)

    The ISBN (we'll try to clean it up if possible)

Returns:

  • (String)

    The converted 10-character ISBN, nil if something looks wrong, or whatever was passed in if it already looked like a 10-digit ISBN



128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/library_stdnums.rb', line 128

def self.convert_to_10 isbn
  isbn = reduce_to_basics isbn, [10,13]

  # Already 10 digits? Just return
  return isbn if isbn.size == 10
  
  # Can't be converted to ISBN-10? Bail
  return nil unless isbn[0..2] == '978'
  
  prefix = isbn[3..11]
  return prefix + self.checkdigit(prefix + '0')
end

+ (String?) convert_to_13(isbn)

To convert to an ISBN13, throw a '978' on the front and compute the checkdigit We leave 13-digit numbers alone, figuring they're already ok. NO CHECKSUM CHECK IS DONE FOR 13-DIGIT ISBNS! and return nil on anything that's not the right length

Parameters:

  • isbn (String)

    The ISBN (we'll try to clean it up if possible)

Returns:

  • (String, nil)

    The converted 13-character ISBN, nil if something looks wrong, or whatever was passed in if it already looked like a 13-digit ISBN



115
116
117
118
119
120
121
# File 'lib/library_stdnums.rb', line 115

def self.convert_to_13 isbn
  isbn = reduce_to_basics isbn, [10,13]
  return nil unless isbn
  return isbn if isbn.size == 13
  prefix = '978' + isbn[0..8]
  return prefix + self.checkdigit(prefix + '0', true)
end

+ (String?) normalize(rawisbn)

For an ISBN normalizing it is the same as converting to ISBN 13 and making sure it's valid

Parameters:

  • isbn (String)

    The ISBN to normalize

Returns:

  • (String, nil)

    the normalized (to 13 digit) ISBN, or nil on failure



100
101
102
103
104
105
106
107
# File 'lib/library_stdnums.rb', line 100

def self.normalize rawisbn
  isbn = convert_to_13 rawisbn
  if isbn and valid?(isbn, true)
    return isbn
  else
    return nil
  end
end

+ (Boolean) valid?(isbn, preprocessed = false)

Check to see if the checkdigit is correct

Parameters:

  • isbn (String)

    The ISBN (we'll try to clean it up if possible)

  • preprocessed (Boolean) (defaults to: false)

    Set to true if the ISBN has already been through reduce_to_basics

Returns:

  • (Boolean)

    Whether or not the checkdigit is correct



87
88
89
90
91
92
93
# File 'lib/library_stdnums.rb', line 87

def self.valid? isbn, preprocessed = false
  return nil if isbn.nil?
  isbn = reduce_to_basics(isbn, [10,13]) unless preprocessed
  return false unless isbn
  return false unless isbn[-1..-1] == self.checkdigit(isbn, true)
  return true
end