usps_intelligent_barcode 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +13 -5
- data/CHANGELOG.markdown +4 -0
- data/Gemfile.lock +3 -0
- data/README.markdown +5 -0
- data/USPS-intelligent-barcode.gemspec +95 -0
- data/VERSION +1 -1
- data/examples/example.rb +1 -1
- data/spec/spec_helper.rb +1 -1
- data/usps_intelligent_barcode.gemspec +4 -19
- metadata +22 -38
- data/lib/USPS-intelligent-barcode/bar_map.rb +0 -52
- data/lib/USPS-intelligent-barcode/bar_position.rb +0 -40
- data/lib/USPS-intelligent-barcode/bar_symbol.rb +0 -49
- data/lib/USPS-intelligent-barcode/bar_to_character_mapping.yml +0 -66
- data/lib/USPS-intelligent-barcode/barcode.rb +0 -152
- data/lib/USPS-intelligent-barcode/barcode_id.rb +0 -98
- data/lib/USPS-intelligent-barcode/character_position.rb +0 -28
- data/lib/USPS-intelligent-barcode/codeword_map.rb +0 -38
- data/lib/USPS-intelligent-barcode/codeword_to_character_mapping.yml +0 -1366
- data/lib/USPS-intelligent-barcode/crc.rb +0 -52
- data/lib/USPS-intelligent-barcode/mailer_id.rb +0 -105
- data/lib/USPS-intelligent-barcode/numeric_conversions.rb +0 -22
- data/lib/USPS-intelligent-barcode/routing_code.rb +0 -134
- data/lib/USPS-intelligent-barcode/serial_number.rb +0 -88
- data/lib/USPS-intelligent-barcode/service_type.rb +0 -79
- data/lib/USPS-intelligent-barcode.rb +0 -17
@@ -1,52 +0,0 @@
|
|
1
|
-
require 'USPS-intelligent-barcode/numeric_conversions'
|
2
|
-
|
3
|
-
module Imb
|
4
|
-
|
5
|
-
# @!group Internal
|
6
|
-
|
7
|
-
# Calculates the Intelligent Mail Barcode CRC.
|
8
|
-
|
9
|
-
class Crc
|
10
|
-
|
11
|
-
include NumericConversions
|
12
|
-
|
13
|
-
# Calculate a CRC.
|
14
|
-
# @param [Integer] binary_data A 102-bit integer
|
15
|
-
# @return [Integer] An 11-bit CRC
|
16
|
-
|
17
|
-
def crc(binary_data)
|
18
|
-
crc = MASK
|
19
|
-
bytes = numeric_to_bytes(binary_data, NUM_INPUT_BYTES)
|
20
|
-
crc = crc_byte(crc, bytes.first, LEADING_BITS_TO_IGNORE)
|
21
|
-
for byte in bytes[1...NUM_INPUT_BYTES]
|
22
|
-
crc = crc_byte(crc, byte, 0)
|
23
|
-
end
|
24
|
-
crc
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
LEADING_BITS_TO_IGNORE = 2
|
30
|
-
CRC_BITS = 11
|
31
|
-
CRC_MSB_MASK = 1 << (CRC_BITS - 1)
|
32
|
-
BITS_PER_BYTE = 8
|
33
|
-
POLYNOMIAL = 0x0F35
|
34
|
-
MASK = (1 << CRC_BITS) - 1
|
35
|
-
NUM_INPUT_BYTES = 13
|
36
|
-
|
37
|
-
def crc_byte(crc, byte, leading_bits_to_ignore)
|
38
|
-
num_bits = BITS_PER_BYTE - leading_bits_to_ignore
|
39
|
-
data = byte << CRC_BITS - BITS_PER_BYTE + leading_bits_to_ignore
|
40
|
-
num_bits.times do
|
41
|
-
use_polynomial = (crc ^ data) & CRC_MSB_MASK
|
42
|
-
crc <<= 1
|
43
|
-
crc ^= POLYNOMIAL if use_polynomial != 0
|
44
|
-
crc &= MASK
|
45
|
-
data <<= 1
|
46
|
-
end
|
47
|
-
crc
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
@@ -1,105 +0,0 @@
|
|
1
|
-
module Imb
|
2
|
-
|
3
|
-
# This class represents a mailer ID.
|
4
|
-
|
5
|
-
class MailerId
|
6
|
-
|
7
|
-
# The allowable range for a short (6-digit) mailer ID
|
8
|
-
SHORT_RANGE = 0..899_999
|
9
|
-
|
10
|
-
# The allowable range for a long (9-digit) mailer ID
|
11
|
-
LONG_RANGE = 900_000_000..999_999_999
|
12
|
-
|
13
|
-
# The list of all allowable ranges for a mailer ID
|
14
|
-
RANGES = [SHORT_RANGE, LONG_RANGE]
|
15
|
-
|
16
|
-
# Turn the argument into a MailerID if possible. Accepts:
|
17
|
-
# * {MailerId}
|
18
|
-
# * String
|
19
|
-
# * Integer
|
20
|
-
# @return [MailerId]
|
21
|
-
# @raise [ArgumentError] If the argument cannot be coerced
|
22
|
-
|
23
|
-
def self.coerce(o)
|
24
|
-
case o
|
25
|
-
when MailerId
|
26
|
-
o
|
27
|
-
when String
|
28
|
-
new(o.to_i)
|
29
|
-
when Integer
|
30
|
-
new(o)
|
31
|
-
else
|
32
|
-
raise ArgumentError, 'Cannot coerce to MailerId'
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
# @param [Integer] value
|
37
|
-
|
38
|
-
def initialize(value)
|
39
|
-
@value = value
|
40
|
-
end
|
41
|
-
|
42
|
-
# Return true if this object is equal to o
|
43
|
-
# @param [Object] o Any object acceptable to {.coerce}
|
44
|
-
|
45
|
-
def ==(o)
|
46
|
-
MailerId.coerce(o).to_i == to_i
|
47
|
-
rescue ArgumentError
|
48
|
-
false
|
49
|
-
end
|
50
|
-
|
51
|
-
# @return [Integer] The value of the mailer ID
|
52
|
-
|
53
|
-
def to_i
|
54
|
-
@value
|
55
|
-
end
|
56
|
-
|
57
|
-
# @!group Internal
|
58
|
-
|
59
|
-
# Return true if this is a long (9 digit) mailer ID
|
60
|
-
|
61
|
-
def long?
|
62
|
-
LONG_RANGE === @value
|
63
|
-
end
|
64
|
-
|
65
|
-
# Validate the value.
|
66
|
-
# @param long_mailer_id truthy if the mailer ID is long (9 digits).
|
67
|
-
# @raise ArgumentError if invalid
|
68
|
-
|
69
|
-
def validate(long_mailer_id)
|
70
|
-
unless in_range?
|
71
|
-
raise ArgumentError, "Must be #{RANGES.join(' or ')}"
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
# Add this object's value to target, shifting it left as many
|
76
|
-
# digts as are needed to make room.
|
77
|
-
# @param [Integer] target The target to be shifted and added to
|
78
|
-
# @param long_mailer_id truthy if the mailer ID is long (9 digits).
|
79
|
-
# @return [Integer] The new value of the target
|
80
|
-
|
81
|
-
def shift_and_add_to(target, long_mailer_id)
|
82
|
-
target * 10 ** num_digits + to_i
|
83
|
-
end
|
84
|
-
|
85
|
-
# @!endgroup
|
86
|
-
|
87
|
-
private
|
88
|
-
|
89
|
-
def in_range?
|
90
|
-
RANGES.any? do |range|
|
91
|
-
range === @value
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
def num_digits
|
96
|
-
if long?
|
97
|
-
9
|
98
|
-
else
|
99
|
-
6
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
end
|
104
|
-
|
105
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
module Imb
|
2
|
-
|
3
|
-
# @!group Internal
|
4
|
-
|
5
|
-
# Numeric conversions
|
6
|
-
|
7
|
-
module NumericConversions
|
8
|
-
|
9
|
-
# Convert a numeric to an array of at least +min_bytes+ bytes.
|
10
|
-
# @param [Numeric] n
|
11
|
-
# @param [Integer] min_bytes
|
12
|
-
# @return [[Integer]] Array of bytes
|
13
|
-
|
14
|
-
def numeric_to_bytes(n, min_bytes=0)
|
15
|
-
n.to_s(16).rjust(2 * min_bytes, '0').scan(/../).map do |s|
|
16
|
-
s.to_i(16)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
@@ -1,134 +0,0 @@
|
|
1
|
-
module Imb
|
2
|
-
|
3
|
-
# Represents a routing code
|
4
|
-
|
5
|
-
class RoutingCode
|
6
|
-
|
7
|
-
# Turn the argument into a RoutingCode if possible. Accepts:
|
8
|
-
# * {RoutingCode}
|
9
|
-
# * nil (no routing code)
|
10
|
-
# * String of length:
|
11
|
-
# * 0 - no routing code
|
12
|
-
# * 5 - zip
|
13
|
-
# * 9 - zip + plus4
|
14
|
-
# * 11 - zip + plus4 + delivery point
|
15
|
-
# * Array of [zip, plus4, delivery point]
|
16
|
-
# @return [RoutingCode]
|
17
|
-
|
18
|
-
def self.coerce(o)
|
19
|
-
case o
|
20
|
-
when nil
|
21
|
-
coerce('')
|
22
|
-
when RoutingCode
|
23
|
-
o
|
24
|
-
when Array
|
25
|
-
RoutingCode.new(*o)
|
26
|
-
when String
|
27
|
-
RoutingCode.new(*string_to_array(o))
|
28
|
-
else
|
29
|
-
raise ArgumentError, 'Cannot coerce to RoutingCode'
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
# @return [Integer] The ZIP (or nil)
|
34
|
-
attr_accessor :zip
|
35
|
-
|
36
|
-
# @return [Integer] The plus4 (or nil)
|
37
|
-
attr_accessor :plus4
|
38
|
-
|
39
|
-
# @return [Integer] The delivery point (or nil)
|
40
|
-
attr_accessor :delivery_point
|
41
|
-
|
42
|
-
# Create a RoutingCode. Arguments are:
|
43
|
-
# * +zip+ - Integer zip (or nil)
|
44
|
-
# * +plus4+ - Integer plus4 (or nil)
|
45
|
-
# * +delivery_point+ - Integer delivery poitn (or nil)
|
46
|
-
|
47
|
-
def initialize(zip, plus4, delivery_point)
|
48
|
-
@zip = arg_to_i(zip)
|
49
|
-
@plus4 = arg_to_i(plus4)
|
50
|
-
@delivery_point = arg_to_i(delivery_point)
|
51
|
-
end
|
52
|
-
|
53
|
-
# Return true if this object is equal to o
|
54
|
-
# @param [Object] o Any object acceptable to {.coerce}
|
55
|
-
|
56
|
-
def ==(o)
|
57
|
-
RoutingCode.coerce(o).to_a == to_a
|
58
|
-
rescue ArgumentError
|
59
|
-
false
|
60
|
-
end
|
61
|
-
|
62
|
-
# @!group Internal
|
63
|
-
|
64
|
-
# Convert a string representation of a routing code into
|
65
|
-
# an array that can be passed to the constructor.
|
66
|
-
# +s+ is a string of length:
|
67
|
-
# * 0 - no routing code
|
68
|
-
# * 5 - zip
|
69
|
-
# * 9 - zip + plus4
|
70
|
-
# * 11 - zip + plus4 + delivery point
|
71
|
-
# The result is an array of [zip, zip4, delivery point]
|
72
|
-
|
73
|
-
def self.string_to_array(s)
|
74
|
-
s = s.gsub(/[\D]/, '')
|
75
|
-
match = /^(?:(\d{5})(?:(\d{4})(\d{2})?)?)?$/.match(s)
|
76
|
-
unless match
|
77
|
-
raise ArgumentError, "Bad routing code: #{s.inspect}"
|
78
|
-
end
|
79
|
-
zip, plus4, delivery_point = match.to_a[1..-1]
|
80
|
-
[zip, plus4, delivery_point]
|
81
|
-
end
|
82
|
-
|
83
|
-
# Validate the value.
|
84
|
-
# @param long_mailer_id truthy if the mailer ID is long (9 digits).
|
85
|
-
# @raise ArgumentError if invalid
|
86
|
-
|
87
|
-
def validate(long_mailer_id)
|
88
|
-
end
|
89
|
-
|
90
|
-
# Add this object's value to target, shifting it left as many
|
91
|
-
# digts as are needed to make room.
|
92
|
-
# @param [Integer] target The target to be shifted and added to
|
93
|
-
# @param long_mailer_id truthy if the mailer ID is long (9 digits).
|
94
|
-
# @return [Integer] The new value of the target
|
95
|
-
|
96
|
-
def shift_and_add_to(target, long_mailer_id)
|
97
|
-
target * 10 ** NUM_DIGITS + convert
|
98
|
-
end
|
99
|
-
|
100
|
-
# @!endgroup
|
101
|
-
|
102
|
-
protected
|
103
|
-
|
104
|
-
# Convert to an array of [zip, plus4, delivery point]
|
105
|
-
|
106
|
-
def to_a
|
107
|
-
[@zip, @plus4, @delivery_point]
|
108
|
-
end
|
109
|
-
|
110
|
-
private
|
111
|
-
|
112
|
-
NUM_DIGITS = 11 #:nodoc:
|
113
|
-
|
114
|
-
def arg_to_i(o)
|
115
|
-
o.andand.to_i
|
116
|
-
end
|
117
|
-
|
118
|
-
# Convert to an integer value
|
119
|
-
|
120
|
-
def convert
|
121
|
-
if @zip && @plus4 && @delivery_point
|
122
|
-
@zip * 1000000 + @plus4 * 100 + @delivery_point + 1000100001
|
123
|
-
elsif @zip && @plus4
|
124
|
-
@zip * 10000 + @plus4 + 100001
|
125
|
-
elsif @zip
|
126
|
-
@zip + 1
|
127
|
-
else
|
128
|
-
0
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
end
|
133
|
-
|
134
|
-
end
|
@@ -1,88 +0,0 @@
|
|
1
|
-
module Imb
|
2
|
-
|
3
|
-
# This class represents the mail piece's serial number.
|
4
|
-
|
5
|
-
class SerialNumber
|
6
|
-
|
7
|
-
# Turn the argument into a SerialNumber if possible. Accepts:
|
8
|
-
# * {SerialNumber}
|
9
|
-
# * String
|
10
|
-
# * Integer
|
11
|
-
# @return [SerialNumber]
|
12
|
-
|
13
|
-
def self.coerce(o)
|
14
|
-
case o
|
15
|
-
when SerialNumber
|
16
|
-
o
|
17
|
-
when String
|
18
|
-
new(o.to_i)
|
19
|
-
when Integer
|
20
|
-
new(o)
|
21
|
-
else
|
22
|
-
raise ArgumentError, 'Cannot coerce to SerialNumber'
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
# @param [Integer] value
|
27
|
-
|
28
|
-
def initialize(value)
|
29
|
-
@value = value
|
30
|
-
end
|
31
|
-
|
32
|
-
# Return true if this object is equal to o
|
33
|
-
# @param [Object] o Any object acceptable to {.coerce}
|
34
|
-
|
35
|
-
def ==(o)
|
36
|
-
SerialNumber.coerce(o).to_i == to_i
|
37
|
-
rescue ArgumentError
|
38
|
-
false
|
39
|
-
end
|
40
|
-
|
41
|
-
# @return [Integer] The value of the serial number
|
42
|
-
|
43
|
-
def to_i
|
44
|
-
@value
|
45
|
-
end
|
46
|
-
|
47
|
-
# @!group Internal
|
48
|
-
|
49
|
-
# Validate the value.
|
50
|
-
# @param long_mailer_id truthy if the mailer ID is long (9 digits).
|
51
|
-
# @raise ArgumentError if invalid
|
52
|
-
|
53
|
-
def validate(long_mailer_id)
|
54
|
-
range = 0..max_value(long_mailer_id)
|
55
|
-
unless range === @value
|
56
|
-
raise ArgumentError, "Must be #{range}"
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
# Add this object's value to target, shifting it left as many
|
61
|
-
# digts as are needed to make room.
|
62
|
-
# @param [Integer] target The target to be shifted and added to
|
63
|
-
# @param long_mailer_id truthy if the mailer ID is long (9 digits).
|
64
|
-
# @return [Integer] The new value of the target
|
65
|
-
|
66
|
-
def shift_and_add_to(target, long_mailer_id)
|
67
|
-
target * 10 ** num_digits(long_mailer_id) + to_i
|
68
|
-
end
|
69
|
-
|
70
|
-
# @!endgroup
|
71
|
-
|
72
|
-
private
|
73
|
-
|
74
|
-
def max_value(long_mailer_id)
|
75
|
-
max_value = 10 ** num_digits(long_mailer_id) - 1
|
76
|
-
end
|
77
|
-
|
78
|
-
def num_digits(long_mailer_id)
|
79
|
-
if long_mailer_id
|
80
|
-
6
|
81
|
-
else
|
82
|
-
9
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
end
|
87
|
-
|
88
|
-
end
|
@@ -1,79 +0,0 @@
|
|
1
|
-
module Imb
|
2
|
-
|
3
|
-
# This class represents a service type.
|
4
|
-
|
5
|
-
class ServiceType
|
6
|
-
|
7
|
-
# The valid range of a service type
|
8
|
-
RANGE = 0..999
|
9
|
-
|
10
|
-
# Turn the argument into a ServiceType if possible. Accepts:
|
11
|
-
# * {ServiceType}
|
12
|
-
# * String
|
13
|
-
# * Integer
|
14
|
-
|
15
|
-
def self.coerce(o)
|
16
|
-
case o
|
17
|
-
when ServiceType
|
18
|
-
o
|
19
|
-
when String
|
20
|
-
new(o.to_i)
|
21
|
-
when Integer
|
22
|
-
new(o)
|
23
|
-
else
|
24
|
-
raise ArgumentError, 'Cannot coerce to ServiceType'
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
# @param [Integer] value
|
29
|
-
|
30
|
-
def initialize(value)
|
31
|
-
@value = value
|
32
|
-
end
|
33
|
-
|
34
|
-
# Return true if this object is equal to o
|
35
|
-
# @param [Object] o Any object acceptable to {.coerce}
|
36
|
-
|
37
|
-
def ==(o)
|
38
|
-
ServiceType.coerce(o).to_i == to_i
|
39
|
-
rescue ArgumentError
|
40
|
-
false
|
41
|
-
end
|
42
|
-
|
43
|
-
# @return [Integer] The value of the service type
|
44
|
-
|
45
|
-
def to_i
|
46
|
-
@value
|
47
|
-
end
|
48
|
-
|
49
|
-
# @!group Internal
|
50
|
-
|
51
|
-
# Validate the value.
|
52
|
-
# @param long_mailer_id truthy if the mailer ID is long (9 digits).
|
53
|
-
# @raise ArgumentError if invalid
|
54
|
-
|
55
|
-
def validate(long_mailer_id)
|
56
|
-
unless (RANGE) === @value
|
57
|
-
raise ArgumentError, "Must be #{RANGE}"
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
# Add this object's value to target, shifting it left as many
|
62
|
-
# digts as are needed to make room.
|
63
|
-
# @param [Integer] target The target to be shifted and added to
|
64
|
-
# @param long_mailer_id truthy if the mailer ID is long (9 digits).
|
65
|
-
# @return [Integer] The new value of the target
|
66
|
-
|
67
|
-
def shift_and_add_to(target, long_mailer_id)
|
68
|
-
target * 10 ** NUM_DIGITS + to_i
|
69
|
-
end
|
70
|
-
|
71
|
-
# @!endgroup
|
72
|
-
|
73
|
-
private
|
74
|
-
|
75
|
-
NUM_DIGITS = 3 #:nodoc:
|
76
|
-
|
77
|
-
end
|
78
|
-
|
79
|
-
end
|