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

.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



164
165
166
167
168
169
170
171
172
173
# File 'lib/library_stdnums.rb', line 164

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)


56
57
58
# File 'lib/library_stdnums.rb', line 56

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



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/library_stdnums.rb', line 66

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



141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/library_stdnums.rb', line 141

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



127
128
129
130
131
132
133
134
# File 'lib/library_stdnums.rb', line 127

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



112
113
114
115
116
117
118
119
# File 'lib/library_stdnums.rb', line 112

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



98
99
100
101
102
103
104
# File 'lib/library_stdnums.rb', line 98

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