require 'barby/barcode' module Barby #EAN-13, aka UPC-A, barcodes are the ones you can see at your local #supermarket, in your house and, well, everywhere.. # #To use this for a UPC barcode, just add a 0 to the front class EAN13 < Barcode1D LEFT_ENCODINGS_ODD = { 0 => '0001101', 1 => '0011001', 2 => '0010011', 3 => '0111101', 4 => '0100011', 5 => '0110001', 6 => '0101111', 7 => '0111011', 8 => '0110111', 9 => '0001011' } LEFT_ENCODINGS_EVEN = { 0 => '0100111', 1 => '0110011', 2 => '0011011', 3 => '0100001', 4 => '0011101', 5 => '0111001', 6 => '0000101', 7 => '0010001', 8 => '0001001', 9 => '0010111' } RIGHT_ENCODINGS = { 0 => '1110010', 1 => '1100110', 2 => '1101100', 3 => '1000010', 4 => '1011100', 5 => '1001110', 6 => '1010000', 7 => '1000100', 8 => '1001000', 9 => '1110100' } #Describes whether the left-hand encoding should use #LEFT_ENCODINGS_ODD or LEFT_ENCODINGS_EVEN, based on the #first digit in the number system (and the barcode as a whole) LEFT_PARITY_MAPS = { 0 => [:odd, :odd, :odd, :odd, :odd, :odd], #UPC-A 1 => [:odd, :odd, :even, :odd, :even, :even], 2 => [:odd, :odd, :even, :even, :odd, :even], 3 => [:odd, :odd, :even, :even, :even, :odd], 4 => [:odd, :even, :odd, :odd, :even, :even], 5 => [:odd, :even, :even, :odd, :odd, :even], 6 => [:odd, :even, :even, :even, :odd, :odd], 7 => [:odd, :even, :odd, :even, :odd, :even], 8 => [:odd, :even, :odd, :even, :even, :odd], 9 => [:odd, :even, :even, :odd, :even, :odd] } #These are the lines that "stick down" in the graphical representation START = '101' CENTER = '01010' STOP = '101' #EAN-13 barcodes have 12 digits + check digit FORMAT = /^\d{12}$/ attr_accessor :data def initialize(data) self.data = data raise ArgumentError, 'data not valid' unless valid? end def characters data.split(//) end def numbers characters.map{|s| s.to_i } end def odd_and_even_numbers alternater = false numbers.reverse.partition{ alternater = !alternater } end #Numbers that are encoded to the left of the center #The first digit is not included def left_numbers numbers[1,6] end #Numbers that are encoded to the right of the center #The checksum is included here def right_numbers numbers_with_checksum[7,6] end def numbers_with_checksum numbers + [checksum] end def data_with_checksum data + checksum.to_s end def left_encodings left_parity_map.zip(left_numbers).map do |parity,number| parity == :odd ? LEFT_ENCODINGS_ODD[number] : LEFT_ENCODINGS_EVEN[number] end end def right_encodings right_numbers.map{|n| RIGHT_ENCODINGS[n] } end def left_encoding left_encodings.join end def right_encoding right_encodings.join end def encoding start_encoding+left_encoding+center_encoding+right_encoding+stop_encoding end #The parities to use for encoding left-hand numbers def left_parity_map LEFT_PARITY_MAPS[numbers.first] end def weighted_sum odds, evens = odd_and_even_numbers odds.map!{|n| n * 3 } (odds+evens).inject(0){|s,n| s+n } end #Mod10 def checksum mod = weighted_sum % 10 mod.zero? ? 0 : 10-mod end def checksum_encoding RIGHT_ENCODINGS[checksum] end def valid? data =~ FORMAT end def to_s data_with_checksum end #Is this a UPC-A barcode? #UPC barcodes are EAN codes that start with 0 def upc? numbers.first.zero? end def start_encoding START end def center_encoding CENTER end def stop_encoding STOP end end class UPCA < EAN13 def data '0' + super end end end