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, Helpers::STDNUMPAT_MULTIPLE

Class Method Summary collapse

Methods included from Helpers

extractNumber, extract_multiple_numbers, reduce_to_basics

Class Method Details

.allNormalizedValues(isbn) ⇒ Array<String,String>?

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



176
177
178
179
180
181
182
183
184
185
# File 'lib/library_stdnums.rb', line 176

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

.at_least_trying?(isbn) ⇒ Boolean

Does it even look like an ISBN?

Returns:

  • (Boolean)


68
69
70
# File 'lib/library_stdnums.rb', line 68

def self.at_least_trying? isbn
  reduce_to_basics(isbn, [10,13]) ? true : false
end

.checkdigit(isbn, preprocessed = false) ⇒ String?

Compute check digits for 10 or 13-digit ISBNs. See algorithm at http://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



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/library_stdnums.rb', line 78

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

.convert_to_10(isbn) ⇒ String

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



153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/library_stdnums.rb', line 153

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

.convert_to_13(isbn) ⇒ String?

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



139
140
141
142
143
144
145
146
# File 'lib/library_stdnums.rb', line 139

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

.normalize(rawisbn) ⇒ String?

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

Parameters:

  • rawisbn (String)

    The ISBN to normalize

Returns:

  • (String, nil)

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



124
125
126
127
128
129
130
131
# File 'lib/library_stdnums.rb', line 124

def self.normalize rawisbn
  isbn = convert_to_13 rawisbn
  if isbn
    return isbn
  else
    return nil
  end
end

.valid?(isbn, preprocessed = false) ⇒ Boolean

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. Sneakily, return 'nil' for values that don't even look like ISBNs, and 'false' for those that look possible but don't normalize / have bad checkdigits



110
111
112
113
114
115
116
# File 'lib/library_stdnums.rb', line 110

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