Class: Identifier::Global::Isbn

Inherits:
Identifier::Global show all
Defined in:
app/models/identifier/global/isbn.rb

Overview

Officially all ISBNs are now 13 digits - however anything published prior to 2007 may have a 10 digit format that requires special processing (see isbn.org) to convert a 10 digit ISBN to a 13 digit ISBN. For our purposes we will allow either a 10 digit or a 13 digit ISBN. - 1/31/2014

From the International ISBN Agency (isbn-international.org/faqs) on 1/31/2014:

Each ISBN consists of 5 parts with each section being separated by spaces or hyphens. Three of the five elements may be of varying length:

Prefix element – currently this can only be either 978 or 979 (it is always 3 digits).
Registration group element – this identifies the particular country, geographical region, or language area
  participating in the ISBN system. This element may be between 1 and 5 digits in length.
Registrant element - this identifies the particular publisher or imprint. This may be up to 7 digits in length.
Publication element – this identifies the particular edition and format of a specific title. This may be up to 6
  digits in length
Check digit – this is always the final single digit that mathematically validates the rest of the number.
  It is calculated using a Modulus 10 system with alternate weights of 1 and 3.

All of this means that it is difficult to validate an ISBN.

validations contains at least 10 digit & only digits, dashes, or spaces validates :identifier, :format => => /A*z/, :message => 'Only digits, spaces and dashes allowed.' doesn't allow blank identifier, because can only create an object if it has an identifier.

Constant Summary

Constant Summary

Constants inherited from Identifier

SHORT_NAMES

Instance Attribute Summary

Attributes inherited from Identifier::Global

#relation

Attributes inherited from Identifier

#cached, #identifier, #identifier_object_id, #namespace_id, #project_id, #type

Instance Method Summary (collapse)

Methods inherited from Identifier::Global

#permit_only_one_global_without_relation_supplied_per_type, #set_cached

Methods inherited from Identifier

#annotated_object, class_name, find_for_autocomplete, generate_download, #klass_name, prototype_identifier, #set_cached

Methods included from Housekeeping

#has_polymorphic_relationship?

Instance Method Details

- (Boolean) ten_or_thirteen_digits?

Returns:

  • (Boolean)


105
106
107
108
109
110
111
112
113
# File 'app/models/identifier/global/isbn.rb', line 105

def ten_or_thirteen_digits?
  # @todo beth will talk to Jim when she gets back from vacation on how to correctly extract only the digits from the string.
  #count = 0
  #carray = self.chars
  #carray.each do |c|
  #  if c.is_digit?
  #end

end

- (Object) using_isbn_class



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'app/models/identifier/global/isbn.rb', line 27

def using_isbn_class
  unless identifier.nil?
    isbn = identifier.upcase
    # 'ISBN-13: 978-0-596-52068-7'
    isbn.gsub!('ISBN-10', '')
    type = $&
    isbn.gsub!('ISBN-13', '')
    type ||= $&
    type.gsub!('ISBN-', '') unless type.nil?
    isbn.gsub!('ISBN', '')
    # ': 978-0-596-52068-7'
    isbn.gsub!(':', '')
    # ' 978-0-596-52068-7'
    isbn.strip!
    # '978-0-596-52068-7' or '978 0 596 52068 7'
    # if there are spaces or hyphens, check to see that they are in the right places
    /^(\d{3}[ -]{0,1}){0,1}\d{1,5}[ -]{0,1}\d{1,5}[ -]{0,1}\d{1,5}[ -]{0,1}(?<last>.)$/ =~ isbn

    isbn.gsub!(' ', '')
    isbn.gsub!('-', '')
    # if there are *any* non-digits left, it is improperly formed
    # NB! 'X' is a valid digit in this case
    /[^\dX]/ =~ isbn
    unless $&.nil?
      errors.add(:identifier, "'#{identifier}' is an improperly formed ISBN.")
      return
    end
    # the final (checksum) digit has alreaqdy been identified, so we need 12 or 9 here
    /^(?<isbn_13>\d{12})\d$|^(?<isbn_10>\d{9}).$/ =~ isbn

    if ($&.nil?) or
        (isbn_10.nil? and isbn_13.nil?) or
        ((isbn_10.nil? and type == '10') or (isbn_13.nil? and type == '13'))
      errors.add(:identifier, "'#{identifier}' has the wrong number of digits.")
      return
    end

    data = isbn.slice(0, isbn.size - 1)
    sum = 0
    index = 0
    # last  = 10 if last == 'X'

    if data.size == 9
      data.reverse!
      data.each_char { |c|
        factor = (index + 2)
        sum += factor * c.to_i
        index += 1
      }

      check_byte = 11 - (sum % 11)
      if check_byte == 10
        check_byte = 'X'
      else
        if check_byte == 11
          check_byte = 0
        end
      end
    else
      data.each_char { |c|
        factor = (((index % 2) * 2) + 1)
        sum += factor * c.to_i
        index += 1
      }
      check_byte = 10 - (sum % 10)
      if check_byte == 10
        check_byte = 0;
      end
    end

    # check_byte and/or last might be an 'X'
    if check_byte.to_s != last
      errors.add(:identifier, "'#{identifier}' has bad check digit.")
      return
    end
  end
end