USPS-intelligent-barcode 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,24 +1,23 @@
1
- # USPS-intelligent-barcode
1
+ = USPS-intelligent-barcode
2
2
 
3
3
  USPS-intelligent-barcode is a pure ruby gem to generate a USPS
4
4
  Intelligent Mail Barcode. More specifically, it generates the string
5
- of characters you should print using one of the [USPS Intelligent
6
- Barcode fonts](https://ribbs.usps.gov/onecodesolution/download.cfm).
5
+ of characters you should print using one of the {USPS Intelligent
6
+ Barcode fonts}[https://ribbs.usps.gov/onecodesolution/download.cfm].
7
7
 
8
- ## FORKED FROM
8
+ == FORKED FROM
9
9
 
10
- This project was forked from :
10
+ This project was forked from
11
+ https://github.com/rtlong/USPS-intelligent-barcode by Ryan Taylor
12
+ Long, in order to add tests and refactor. It is _not_ a drop-in
13
+ replacement: I renamed most methods and classes, and eliminated the
14
+ #draw method.
11
15
 
12
- [rtlong/USPS-intellient-barcode](https://github.com/rtlong/USPS-intelligent-barcode)
13
- (github) by Ryan Taylor Long, in order to add tests and refactor. It
14
- is _not_ a drop-in replacement: I renamed most methods and classes,
15
- and eliminated the #draw method.
16
-
17
- ## INSTALL
16
+ == INSTALL
18
17
 
19
18
  $ gem install USPS-intelligent-barcode
20
19
 
21
- ## EXAMPLE
20
+ == EXAMPLE
22
21
 
23
22
  #!/usr/bin/env ruby
24
23
 
@@ -38,20 +37,20 @@ and eliminated the #draw method.
38
37
  p barcode.barcode_letters
39
38
  # => "AADTFFDFTDADTAADAATFDTDDAAADDTDTTDAFADADDDTFFFDDTTTADFAAADFTDAADA"
40
39
 
41
- ## STANDARD
40
+ == STANDARD
42
41
 
43
42
  This gem is based upon standard
44
- [USPS-B-3200G](https://ribbs.usps.gov/intelligentmail_mailpieces/documents/tech_guides/SPUSPSG.pdf)
43
+ {USPS-B-3200G}[https://ribbs.usps.gov/intelligentmail_mailpieces/documents/tech_guides/SPUSPSG.pdf]
45
44
 
46
- ## RUBY VERSIONS
45
+ == RUBY VERSIONS
47
46
 
48
47
  The tests are known to pass in MRI 1.8.7 and MRI 1.9.3
49
48
 
50
- ## WHOAMI
49
+ == WHOAMI
51
50
 
52
51
  Wayne Conrad <wconrad@yagni.com>
53
52
 
54
- ## CREDITS
53
+ == CREDITS
55
54
 
56
55
  Thanks to Ryan Taylor Long for his original work, without which I
57
56
  would have been lost in the USPS specification.
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "USPS-intelligent-barcode"
8
- s.version = "0.1.2"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Wayne Conrad"]
@@ -14,13 +14,13 @@ Gem::Specification.new do |s|
14
14
  s.email = "wayne@databill.com"
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE.md",
17
- "README.md"
17
+ "README.rdoc"
18
18
  ]
19
19
  s.files = [
20
20
  "Gemfile",
21
21
  "Gemfile.lock",
22
22
  "LICENSE.md",
23
- "README.md",
23
+ "README.rdoc",
24
24
  "Rakefile",
25
25
  "USPS-intelligent-barcode.gemspec",
26
26
  "VERSION",
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.2.0
@@ -1,15 +1,41 @@
1
+ # The namespace for everything in this gem.
2
+
1
3
  module Imb
2
4
 
5
+ # This class represents a barcode
6
+
3
7
  class Barcode
4
8
 
5
9
  include Memoizer
6
10
 
11
+ # The barcode id, an instance of BarcodeId
7
12
  attr_reader :barcode_id
13
+
14
+ # The service type, an instance of ServiceType
8
15
  attr_reader :service_type
16
+
17
+ # The mailer id, an instance of MailerId
9
18
  attr_reader :mailer_id
19
+
20
+ # The serial number, and instance of SerialNumber
10
21
  attr_reader :serial_number
22
+
23
+ # The routing code, an instance of RoutingCode
11
24
  attr_reader :routing_code
12
25
 
26
+ # === Arguments
27
+
28
+ # * +barcode_id+ - Nominally a String, but can be anything that
29
+ # BarcodeId::coerce will accept.
30
+ # * +service_type+ - Nominally a String, but can be anything that
31
+ # ServiceType::coerce will accept.
32
+ # * +mailer_id+ - Nominally a String, but can be anything that
33
+ # MailerId::coerce will accept.
34
+ # * +serial_number+ - Nominally a String, but can be anything that
35
+ # SerialNumber::coerce will accept.
36
+ # * +routing_code+ - Nominally a String, but can be anything that
37
+ # RoutingCode::coerce will accept.
38
+
13
39
  def initialize(barcode_id,
14
40
  service_type,
15
41
  mailer_id,
@@ -22,15 +48,26 @@ module Imb
22
48
  @routing_code = RoutingCode.coerce(routing_code)
23
49
  validate_components
24
50
  end
25
-
51
+
52
+ # Return a string that represents the barcode. Each character of
53
+ # the string will be one of:
54
+ # * 'T' for a tracking mark (neither ascender nor descender)
55
+ # * 'A' for an ascender mark
56
+ # * 'D' for a descender mark
57
+ # * 'F' for a full mark (both ascender and descender)
58
+ # Print the barcode using this string and one of the USPS
59
+ # Intelligent Mail Barcode fonts
60
+
26
61
  def barcode_letters
27
62
  barcode.map { |bar| "TDAF"[bar..bar] }.join
28
63
  end
29
64
 
30
65
  private
31
66
 
67
+ # :stopdoc:
32
68
  BAR_MAP = BarMap.new
33
69
  CODEWORD_MAP = CodewordMap.new
70
+ # :startdoc:
34
71
 
35
72
  def validate_components
36
73
  components.each do |component|
@@ -1,7 +1,20 @@
1
1
  module Imb
2
2
 
3
+ # This class represents a Barcode ID
4
+
3
5
  class BarcodeId
4
6
 
7
+ # The allowable range of a barcode ID
8
+ RANGE = 0..94
9
+
10
+ # The allowable range of a barcode ID's least significant digit
11
+ LSD_RANGE = 0..4
12
+
13
+ # Turn the argument into a BarcodeID if possible. Accepts:
14
+ # * BarcodeId
15
+ # * String
16
+ # * Integer
17
+
5
18
  def self.coerce(o)
6
19
  case o
7
20
  when BarcodeId
@@ -15,32 +28,36 @@ module Imb
15
28
  end
16
29
  end
17
30
 
31
+ # Create a new BarcodeId
32
+ # * +value+ - The integer value of the barcode ID
33
+
18
34
  def initialize(value)
19
35
  @value = value
20
36
  end
21
37
 
38
+ # Validate the value. Raises ArgumentError if out of range.
39
+ # * +long_mailer_id+ - truthy if the mailer ID is long (9 digits).
40
+
22
41
  def validate(long_mailer_id)
23
42
  unless RANGE === @value
24
43
  raise ArgumentError, "Must be #{RANGE}"
25
44
  end
26
- unless LSB_RANGE === least_significant_digit
27
- raise ArgumentError, "Least significant digit must be #{LSB_RANGE}"
45
+ unless LSD_RANGE === least_significant_digit
46
+ raise ArgumentError, "Least significant digit must be #{LSD_RANGE}"
28
47
  end
29
48
  end
30
49
 
50
+ # Return true if +o+ is equal. +o+ may be any object which ::coerce
51
+ # can turn into a BarcodeId.
52
+
31
53
  def ==(o)
32
54
  BarcodeId.coerce(o).to_i == to_i
33
55
  rescue ArgumentError
34
56
  false
35
57
  end
36
58
 
37
- def most_significant_digit
38
- @value / 10
39
- end
40
-
41
- def least_significant_digit
42
- @value % 10
43
- end
59
+ # Add this object's value to target, shifting it left as many
60
+ # digts as are needed to make room.
44
61
 
45
62
  def shift_and_add_to(target, long_mailer_id)
46
63
  target *= 10
@@ -50,7 +67,7 @@ module Imb
50
67
  target
51
68
  end
52
69
 
53
- protected
70
+ # Return the integer value of the barcode ID
54
71
 
55
72
  def to_i
56
73
  @value
@@ -58,8 +75,13 @@ module Imb
58
75
 
59
76
  private
60
77
 
61
- RANGE = 0..94
62
- LSB_RANGE = 0..4
78
+ def most_significant_digit
79
+ @value / 10
80
+ end
81
+
82
+ def least_significant_digit
83
+ @value % 10
84
+ end
63
85
 
64
86
  end
65
87
 
@@ -1,7 +1,23 @@
1
1
  module Imb
2
2
 
3
+ # This class represents a mailer ID.
4
+
3
5
  class MailerId
4
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
+
5
21
  def self.coerce(o)
6
22
  case o
7
23
  when MailerId
@@ -15,31 +31,45 @@ module Imb
15
31
  end
16
32
  end
17
33
 
34
+ # Create a new MailerId.
35
+ # * +value+ - The integer value of the MailerId
36
+
18
37
  def initialize(value)
19
38
  @value = value
20
39
  end
21
40
 
41
+ # Validate the value. Raises ArgumentError if out of range.
42
+ # * +long_mailer_id+ - truthy if the mailer ID is long (9 digits).
43
+
22
44
  def validate(long_mailer_id)
23
45
  unless in_range?
24
46
  raise ArgumentError, "Must be #{RANGES.join(' or ')}"
25
47
  end
26
48
  end
27
49
 
50
+ # Return true if +o+ is equal. +o+ may be any object which ::coerce
51
+ # can turn into a MailerId.
52
+
28
53
  def ==(o)
29
54
  MailerId.coerce(o).to_i == to_i
30
55
  rescue ArgumentError
31
56
  false
32
57
  end
33
58
 
59
+ # Return true if this is a long (9 digit) mailer ID
60
+
34
61
  def long?
35
62
  LONG_RANGE === @value
36
63
  end
37
64
 
65
+ # Add this object's value to target, shifting it left as many
66
+ # digts as are needed to make room.
67
+
38
68
  def shift_and_add_to(target, long_mailer_id)
39
69
  target * 10 ** num_digits + to_i
40
70
  end
41
71
 
42
- protected
72
+ # Return the integer value of the mailer ID
43
73
 
44
74
  def to_i
45
75
  @value
@@ -47,10 +77,6 @@ module Imb
47
77
 
48
78
  private
49
79
 
50
- SHORT_RANGE = 0..899_999
51
- LONG_RANGE = 900_000_000..999_999_999
52
- RANGES = [SHORT_RANGE, LONG_RANGE]
53
-
54
80
  def in_range?
55
81
  RANGES.any? do |range|
56
82
  range === @value
@@ -2,6 +2,16 @@ module Imb
2
2
 
3
3
  class RoutingCode
4
4
 
5
+ # Turn the argument into a RoutingCode if possible. Accepts:
6
+ # * RoutingCode
7
+ # * nil (no routing code)
8
+ # * String of length:
9
+ # * 0 - no routing code
10
+ # * 5 - zip
11
+ # * 9 - zip + plus4
12
+ # * 11 - zip + plus4 + delivery point
13
+ # * Array of [zip, plus4, delivery point]
14
+
5
15
  def self.coerce(o)
6
16
  case o
7
17
  when nil
@@ -17,6 +27,15 @@ module Imb
17
27
  end
18
28
  end
19
29
 
30
+ # Convert a string representation of a routing code into
31
+ # an array that can be passed to the constructor.
32
+ # +s+ is a string of length:
33
+ # * 0 - no routing code
34
+ # * 5 - zip
35
+ # * 9 - zip + plus4
36
+ # * 11 - zip + plus4 + delivery point
37
+ # The result is an array of [zip, zip4, delivery point]
38
+
20
39
  def self.string_to_array(s)
21
40
  s = s.gsub(/[\D]/, '')
22
41
  match = /^(?:(\d{5})(?:(\d{4})(\d{2})?)?)?$/.match(s)
@@ -27,32 +46,34 @@ module Imb
27
46
  [zip, plus4, delivery_point]
28
47
  end
29
48
 
30
- attr_accessor :zip, :plus4, :delivery_point
49
+ # Return the ZIP (or nil)
50
+ attr_accessor :zip
51
+
52
+ # Return the plus4 (or nil)
53
+ attr_accessor :plus4
54
+
55
+ # Return the delivery point (or nil)
56
+ attr_accessor :delivery_point
31
57
 
58
+ # Create a RoutingCode. Arguments are:
59
+ # * +zip+ - Integer zip (or nil)
60
+ # * +plus4+ - Integer plus4 (or nil)
61
+ # * +delivery_point+ - Integer delivery poitn (or nil)
62
+
32
63
  def initialize(zip, plus4, delivery_point)
33
64
  @zip = arg_to_i(zip)
34
65
  @plus4 = arg_to_i(plus4)
35
66
  @delivery_point = arg_to_i(delivery_point)
36
67
  end
37
68
 
69
+ # Validate the value. Raises ArgumentError if out of range.
70
+ # * +long_mailer_id+ - truthy if the mailer ID is long (9 digits).
71
+
38
72
  def validate(long_mailer_id)
39
73
  end
40
-
41
- def convert
42
- if @zip && @plus4 && @delivery_point
43
- @zip * 1000000 + @plus4 * 100 + @delivery_point + 1000100001
44
- elsif @zip && @plus4
45
- @zip * 10000 + @plus4 + 100001
46
- elsif @zip
47
- @zip + 1
48
- else
49
- 0
50
- end
51
- end
52
74
 
53
- def to_a
54
- [@zip, @plus4, @delivery_point]
55
- end
75
+ # Return true if +o+ is equal. +o+ may be any object which ::coerce
76
+ # can turn into a RoutingCode.
56
77
 
57
78
  def ==(o)
58
79
  RoutingCode.coerce(o).to_a == to_a
@@ -60,17 +81,42 @@ module Imb
60
81
  false
61
82
  end
62
83
 
84
+ # Add this object's value to target, shifting it left as many
85
+ # digts as are needed to make room.
86
+
63
87
  def shift_and_add_to(target, long_mailer_id)
64
88
  target * 10 ** NUM_DIGITS + convert
65
89
  end
66
90
 
91
+ protected
92
+
93
+ # Convert to an array of [zip, plus4, delivery point]
94
+
95
+ def to_a
96
+ [@zip, @plus4, @delivery_point]
97
+ end
98
+
67
99
  private
68
100
 
69
- NUM_DIGITS = 11
101
+ NUM_DIGITS = 11 #:nodoc:
70
102
 
71
103
  def arg_to_i(o)
72
104
  o.andand.to_i
73
105
  end
106
+
107
+ # Convert to an integer value
108
+
109
+ def convert
110
+ if @zip && @plus4 && @delivery_point
111
+ @zip * 1000000 + @plus4 * 100 + @delivery_point + 1000100001
112
+ elsif @zip && @plus4
113
+ @zip * 10000 + @plus4 + 100001
114
+ elsif @zip
115
+ @zip + 1
116
+ else
117
+ 0
118
+ end
119
+ end
74
120
 
75
121
  end
76
122
 
@@ -1,7 +1,14 @@
1
1
  module Imb
2
2
 
3
+ # This class represents the mail piece's serial number.
4
+
3
5
  class SerialNumber
4
6
 
7
+ # Turn the argument into a SerialNumber if possible. Accepts:
8
+ # * SerialNumber
9
+ # * String
10
+ # * Integer
11
+
5
12
  def self.coerce(o)
6
13
  case o
7
14
  when SerialNumber
@@ -15,10 +22,15 @@ module Imb
15
22
  end
16
23
  end
17
24
 
25
+ # Create a new serial number from an integer.
26
+
18
27
  def initialize(value)
19
28
  @value = value
20
29
  end
21
30
 
31
+ # Validate the value. Raises ArgumentError if out of range.
32
+ # * +long_mailer_id+ - truthy if the mailer ID is long (9 digits).
33
+
22
34
  def validate(long_mailer_id)
23
35
  range = 0..max_value(long_mailer_id)
24
36
  unless range === @value
@@ -26,17 +38,23 @@ module Imb
26
38
  end
27
39
  end
28
40
 
41
+ # Return true if +o+ is equal. +o+ may be any object which ::coerce
42
+ # can turn into a SerialNumber.
43
+
29
44
  def ==(o)
30
45
  SerialNumber.coerce(o).to_i == to_i
31
46
  rescue ArgumentError
32
47
  false
33
48
  end
34
49
 
50
+ # Add this object's value to target, shifting it left as many
51
+ # digts as are needed to make room.
52
+
35
53
  def shift_and_add_to(target, long_mailer_id)
36
54
  target * 10 ** num_digits(long_mailer_id) + to_i
37
55
  end
38
56
 
39
- protected
57
+ # Return the integer value of the serial number
40
58
 
41
59
  def to_i
42
60
  @value
@@ -2,6 +2,14 @@ module Imb
2
2
 
3
3
  class ServiceType
4
4
 
5
+ # The valid range of a service type
6
+ RANGE = 0..999
7
+
8
+ # Turn the argument into a ServiceType if possible. Accepts:
9
+ # * ServiceType
10
+ # * String
11
+ # * Integer
12
+
5
13
  def self.coerce(o)
6
14
  case o
7
15
  when ServiceType
@@ -15,27 +23,38 @@ module Imb
15
23
  end
16
24
  end
17
25
 
26
+ # Create a service type from an integer
27
+
18
28
  def initialize(value)
19
29
  @value = value
20
30
  end
21
31
 
32
+ # Validate the value. Raises ArgumentError if out of range.
33
+ # * +long_mailer_id+ - truthy if the mailer ID is long (9 digits).
34
+
22
35
  def validate(long_mailer_id)
23
36
  unless (RANGE) === @value
24
37
  raise ArgumentError, "Must be #{RANGE}"
25
38
  end
26
39
  end
27
40
 
41
+ # Return true if +o+ is equal. +o+ may be any object which ::coerce
42
+ # can turn into a ServiceType.
43
+
28
44
  def ==(o)
29
45
  ServiceType.coerce(o).to_i == to_i
30
46
  rescue ArgumentError
31
47
  false
32
48
  end
33
49
 
50
+ # Add this object's value to target, shifting it left as many
51
+ # digts as are needed to make room.
52
+
34
53
  def shift_and_add_to(target, long_mailer_id)
35
54
  target * 10 ** NUM_DIGITS + to_i
36
55
  end
37
56
 
38
- protected
57
+ # Return the integer value of the service type
39
58
 
40
59
  def to_i
41
60
  @value
@@ -43,8 +62,7 @@ module Imb
43
62
 
44
63
  private
45
64
 
46
- RANGE = 0..999
47
- NUM_DIGITS = 3
65
+ NUM_DIGITS = 3 #:nodoc:
48
66
 
49
67
  end
50
68
 
@@ -51,18 +51,6 @@ module Imb
51
51
  specify {o1.should_not == o4}
52
52
  end
53
53
 
54
- describe '#most_significant_digit' do
55
- specify do
56
- BarcodeId.new(12).most_significant_digit.should == 1
57
- end
58
- end
59
-
60
- describe '#least_significant_digit' do
61
- specify do
62
- BarcodeId.new(12).least_significant_digit.should == 2
63
- end
64
- end
65
-
66
54
  describe '#validate' do
67
55
 
68
56
  let(:long_mailer_id?) {mock 'long_mailer_id?'}
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: USPS-intelligent-barcode
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 1
9
8
  - 2
10
- version: 0.1.2
9
+ - 0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Wayne Conrad
@@ -85,12 +85,12 @@ extensions: []
85
85
 
86
86
  extra_rdoc_files:
87
87
  - LICENSE.md
88
- - README.md
88
+ - README.rdoc
89
89
  files:
90
90
  - Gemfile
91
91
  - Gemfile.lock
92
92
  - LICENSE.md
93
- - README.md
93
+ - README.rdoc
94
94
  - Rakefile
95
95
  - USPS-intelligent-barcode.gemspec
96
96
  - VERSION