Class: Barcode1DTools::UPC_Supplemental_5

Inherits:
Barcode1D
  • Object
show all
Defined in:
lib/barcode1dtools/upc_supplemental_5.rb

Constant Summary collapse

LEFT_PATTERNS =

The bar patterns are the left bar patterns of UPC-A/EAN-13

UPC_A::LEFT_PATTERNS
LEFT_PATTERNS_RLE =

The rle bar patterns are the left bar patterns of UPC-A/EAN-13

UPC_A::LEFT_PATTERNS_RLE
PARITY_PATTERNS =

Parity patterns, essentially binary counting where “e” is “1” and “o” is “0”.

{
  '0' => 'eeooo',
  '1' => 'eoeoo',
  '2' => 'eooeo',
  '3' => 'eoooe',
  '4' => 'oeeoo',
  '5' => 'ooeeo',
  '6' => 'oooee',
  '7' => 'oeoeo',
  '8' => 'oeooe',
  '9' => 'ooeoe'
}
LEFT_GUARD_PATTERN =

Left guard pattern

'1011'
MIDDLE_GUARD_PATTERN =

Middle guard pattern

'01'
LEFT_GUARD_PATTERN_RLE =

Left guard pattern as an rle

'112'
MIDDLE_GUARD_PATTERN_RLE =

Middle guard pattern as an rle

'11'
DEFAULT_OPTIONS =
{
  :line_character => '1',
  :space_character => '0'
}

Instance Attribute Summary collapse

Attributes inherited from Barcode1D

#check_digit, #encoded_string, #options, #value

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Barcode1D

bar_pair, bars_to_rle, rle_to_bars, rle_to_wn, wn_pair, wn_to_rle

Constructor Details

#initialize(value, options = {}) ⇒ UPC_Supplemental_5

Creates a new UPC_Supplemental_5 object with the given value. Options are :line_character, :space_character, and :checksum_included.



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/barcode1dtools/upc_supplemental_5.rb', line 217

def initialize(value, options = {})

  @options = DEFAULT_OPTIONS.merge(options)

  # Can we encode this value?
  raise UnencodableCharactersError unless self.class.can_encode?(value, @options)

  if @options[:checksum_included]
    @encoded_string = value.to_s
    raise ChecksumError unless self.class.validate_check_digit_for(@encoded_string)
    md = @encoded_string.match(/^(\d+?)(\d)$/)
    @value, @check_digit = md[1], md[2].to_i
  else
    # need to add a checksum
    @value = value.to_s
    @check_digit = self.class.generate_check_digit_for(@value)
    @encoded_string = sprintf('%05d%1d',@value.to_i,@check_digit)
  end

  md = @value.match(/^(\d)(\d{4})/)
  @currency_code, @price = md[1], md[2]
end

Instance Attribute Details

#currency_codeObject (readonly)

Specific to a UPC Supp 5 - the currency code part of the value



123
124
125
# File 'lib/barcode1dtools/upc_supplemental_5.rb', line 123

def currency_code
  @currency_code
end

#priceObject (readonly)

Specific to a UPC Supp 5 - the price part of the value



125
126
127
# File 'lib/barcode1dtools/upc_supplemental_5.rb', line 125

def price
  @price
end

Class Method Details

.can_encode?(value, options = nil) ⇒ Boolean

Returns true or false - must be 5 or 6 digits. This also handles the case where the leading 0 is added.

Returns:

  • (Boolean)


130
131
132
133
134
135
136
137
138
# File 'lib/barcode1dtools/upc_supplemental_5.rb', line 130

def can_encode?(value, options = nil)
  if !options
    value.to_s =~ /^\d{5,6}$/
  elsif (options[:checksum_included])
    value.to_s =~ /^\d{6}$/
  else
    value.to_s =~ /^\d{5}$/
  end
end

.decode(str) ⇒ Object

Decodes a bar pattern or RLE pattern and returns a UPC_Supplemental_5 object with the value.



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/barcode1dtools/upc_supplemental_5.rb', line 157

def decode(str)
  if str.length == 47
    # bar pattern
    str = bars_to_rle(str)
  elsif str.length == 31 && str =~ /^[1-9]+$/
    # rle
  else
    raise UnencodableCharactersError, "Pattern must be 47 unit bar pattern or 31 character rle."
  end

  # This string is "aaabbbb(ccdddd)" where "aaa" is the left
  # guard pattern, "bbbb" is the first digit, "cc" is the
  # intra-digit guard pattern, and "dddd" is the second
  # digit.  (ccdddd) occurs 4 times.

  # Check the guard patterns
  unless (str[0..2] == LEFT_GUARD_PATTERN_RLE && [7,13,19,25].all? { |x| str[x,2] == MIDDLE_GUARD_PATTERN_RLE.reverse })
    raise UnencodableCharactersError, "Missing or incorrect guard patterns"
  end

  parity_sequence = ''
  digits = ''
  left_initial_offset = LEFT_GUARD_PATTERN_RLE.length

  # Decode
  (0..4).each do |left_offset|
    found = false
    digit_rle = str[(left_initial_offset + left_offset*6),4]
    ['o','e'].each do |parity|
      ('0'..'9').each do |digit|
        if LEFT_PATTERNS_RLE[digit][parity] == digit_rle
          parity_sequence += parity
          digits += digit
          found = true
          break
        end
      end
    end
    raise UndecodableCharactersError, "Invalid sequence: #{digit_rle}" unless found
  end

  # Now, find the parity digit
  parity_digit = nil
  ('0'..'9').each do |x|
    if PARITY_PATTERNS[x] == parity_sequence
      parity_digit = x
      break
    end
  end

  raise UndecodableCharactersError, "Weird parity: #{parity_sequence}" unless parity_digit

  UPC_Supplemental_5.new(digits + parity_digit, :checksum_included => true)
end

.generate_check_digit_for(value) ⇒ Object

Generates check digit given a string to encode. It assumes there is no check digit on the “value”.



142
143
144
145
# File 'lib/barcode1dtools/upc_supplemental_5.rb', line 142

def generate_check_digit_for(value)
  mult = 9  # alternates 3 and 9
  sprintf('%05d',value.to_i).reverse.chars.inject(0) { |a,c| mult = 12 - mult; a + c.to_i * mult } % 10
end

.validate_check_digit_for(value) ⇒ Object

Validates the check digit given a string - assumes check digit is last digit of string.



149
150
151
152
153
# File 'lib/barcode1dtools/upc_supplemental_5.rb', line 149

def validate_check_digit_for(value)
  raise UnencodableCharactersError unless self.can_encode?(value, :checksum_included => true)
  md = value.match(/^(\d{5})(\d)$/)
  self.generate_check_digit_for(md[1]) == md[2].to_i
end

Instance Method Details

#barsObject

Returns a simple bar pattern.



256
257
258
# File 'lib/barcode1dtools/upc_supplemental_5.rb', line 256

def bars
  @bars ||= self.class.rle_to_bars(self.rle, @options)
end

#rleObject

Returns a run-length-encoded string representation.



246
247
248
249
250
251
252
253
# File 'lib/barcode1dtools/upc_supplemental_5.rb', line 246

def rle
  if @rle
    @rle
  else
    md = @encoded_string.match(/(\d{5})(\d)$/)
    @rle = gen_rle(md[1], md[2])
  end
end

#widthObject

Returns the total unit width of the bar code.



261
262
263
# File 'lib/barcode1dtools/upc_supplemental_5.rb', line 261

def width
  @width ||= rle.split('').inject(0) { |a,c| a + c.to_i }
end

#wnObject

W/N patterns are not usable with EAN-style codes.



241
242
243
# File 'lib/barcode1dtools/upc_supplemental_5.rb', line 241

def wn
  raise NotImplementedError
end