class Imb::Barcode

This class represents a barcode.

Attributes

barcode_id[R]

@return [BarcodeId]

mailer_id[R]

@return [MailerId]

routing_code[R]

@return [RoutingCode]

serial_number[R]

@return [SerialNumber]

service_type[R]

@return [ServiceType]

Public Class Methods

new( barcode_id, service_type, mailer_id, serial_number, routing_code ) click to toggle source

Create a new barcode

@param barcode_id [String] Nominally a String, but can be

anything that {BarcodeId.coerce} will accept.

@param service_type [String] Nominally a String, but can be

anything that {ServiceType.coerce} will accept.

@param mailer_id [String] Nominally a String, but can be

anything that {MailerId.coerce} will accept.

@param serial_number [String] Nominally a String, but can be

anything that {SerialNumber.coerce} will accept.

@param routing_code [String] Nominally a String, but can be

anything that {RoutingCode.coerce} will accept.
# File lib/usps_intelligent_barcode/barcode.rb, line 43
def initialize(
      barcode_id,
      service_type,
      mailer_id,
      serial_number,
      routing_code
    )
  @barcode_id = BarcodeId.coerce(barcode_id)
  @service_type = ServiceType.coerce(service_type)
  @mailer_id = MailerId.coerce(mailer_id)
  @serial_number = SerialNumber.coerce(serial_number)
  @routing_code = RoutingCode.coerce(routing_code)
  validate_components
end

Public Instance Methods

barcode_letters() click to toggle source

Return a string to print using one of the USPS Intelligent Mail Barcode fonts. Each character of the string will be one of:

  • 'T' for a tracking mark (neither ascender nor descender)

  • 'A' for an ascender mark

  • 'D' for a descender mark

  • 'F' for a full mark (both ascender and descender)

@return [String] A string that represents the barcode.

# File lib/usps_intelligent_barcode/barcode.rb, line 65
def barcode_letters
  symbols.map(&:letter).join
end

Private Instance Methods

binary_data() click to toggle source

The components (“fields” in the spec) are turned into a single number that the spec calls “binary_data”). This is done through a series of multiplications and additions. See spec. section 2.2.1 (“Step 1–Conversion of Data Fields into Binary Data”).

@return [Integer]

# File lib/usps_intelligent_barcode/barcode.rb, line 103
def binary_data
  components.inject(0) do |data, component|
    component.shift_and_add_to(data, long_mailer_id?)
  end
end
characters() click to toggle source

Convert the codewords to “characters”. Each character is a 13-bit integer; there are 10 of them, labeled “A” through “J” by the spec. See spec. section 2.2.5 (“Step 5–Conversion from Codewords to Characters”), para. “A”.

@return [Array<Integer>] 10 “characters.”

# File lib/usps_intelligent_barcode/barcode.rb, line 165
def characters
  CODEWORD_MAP.characters(codewords_with_fcs_bit_in_character_a)
end
characters_with_fcs_bits_0_through_9() click to toggle source

Fold the least-significant 10 bits of the FCS into the “characters”. See spec. section 2.2.5 (“Step 5–Conversion from Codewords to Characters”), para. “B”.

@return [Array<Integer>] 10 “characters”.

# File lib/usps_intelligent_barcode/barcode.rb, line 174
def characters_with_fcs_bits_0_through_9
  characters.each_with_index.map do |character, i|
    if frame_check_sequence[i] == 1
      character ^ 0b1111111111111
    else
      character
    end
  end
end
codewords() click to toggle source

Compute the “code words.” This is an array of 10 integers computed from the binary data. See spec. section 2.2.3 (“Step 3–Conversion from Binary Data to Codewords”).

@return [Array<Integer>] 10 “characters.”

# File lib/usps_intelligent_barcode/barcode.rb, line 124
def codewords
  codewords = []
  data = binary_data
  data, codewords[9] = data.divmod 636
  8.downto(0) do |i|
    data, codewords[i] = data.divmod 1365
  end
  codewords
end
codewords_with_fcs_bit_in_character_a() click to toggle source

Insert the most significant bit of the FCS into codeword A. See spec. section 2.4.4 (“Step 4–Inserting Additional Information into Codewords”).

@return [Array<Integer>] 10 “characters.”

# File lib/usps_intelligent_barcode/barcode.rb, line 153
def codewords_with_fcs_bit_in_character_a
  result = codewords_with_orientation_in_character_j.dup
  result[0] += 659 if frame_check_sequence[10] == 1
  result
end
codewords_with_orientation_in_character_j() click to toggle source

Insert the orientation into the codewords. The spec. doesn't say much about this, other than to multiply codeword “J” by two. This will cause the LSB to be zero, which is presumably the orientation. See spec. section 2.4.4 (“Step 4–Inserting Additional Information into Codewords”).

@return [Array<Integer>] 10 “characters.”

# File lib/usps_intelligent_barcode/barcode.rb, line 142
def codewords_with_orientation_in_character_j
  result = codewords.dup
  result[9] *= 2
  result
end
components() click to toggle source
# File lib/usps_intelligent_barcode/barcode.rb, line 83
def components
  [
    @routing_code,
    @barcode_id,
    @service_type,
    @mailer_id,
    @serial_number,
  ]
end
frame_check_sequence() click to toggle source

Compute the “frame check sequence.” See spec. section 2.2.2 (“Step 2–Generation of 11-Bit CRC on Binary Data”).

@return [Integer]

# File lib/usps_intelligent_barcode/barcode.rb, line 114
def frame_check_sequence
  CRC.crc(binary_data)
end
long_mailer_id?() click to toggle source
# File lib/usps_intelligent_barcode/barcode.rb, line 93
def long_mailer_id?
  @mailer_id.long?
end
symbols() click to toggle source

Map the “characters” to symbols. Here is where the barcode is made.

@return [Array<BarSymbol>]

# File lib/usps_intelligent_barcode/barcode.rb, line 187
def symbols
  BAR_MAP.symbols(characters_with_fcs_bits_0_through_9)
end
validate_components() click to toggle source
# File lib/usps_intelligent_barcode/barcode.rb, line 77
def validate_components
  components.each do |component|
    component.validate(long_mailer_id?)
  end
end