barcode1dtools 0.9.7.0 → 0.9.8.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.
@@ -17,8 +17,9 @@ module Barcode1DTools
17
17
  # library currently includes EAN-13, EAN-8, UPC-A, UPC-E, UPC
18
18
  # Supplemental 2, UPC Supplemental 5, Interleaved 2 of 5 (I 2/5),
19
19
  # COOP 2 of 5, Matrix 2 of 5, Industrial 2 of 5, IATA 2 of 5,
20
- # PostNet, Code 3 of 9, Code 93, Code 11, and Codabar, but will
21
- # be expanded to include most 1D symbologies in the near future.
20
+ # PostNet, Plessey, MSI (Modified Plessey), Code 3 of 9, Code 93,
21
+ # Code 11, and Codabar, but will be expanded to include most 1D
22
+ # symbologies in the near future.
22
23
  #
23
24
  #== Example
24
25
  # ean13 = Barcode1DTools::EAN13.new('0012676510226', :line_character => 'x', :space_character => ' ')
@@ -127,3 +128,5 @@ require 'barcode1dtools/industrial2of5'
127
128
  require 'barcode1dtools/iata2of5'
128
129
  require 'barcode1dtools/matrix2of5'
129
130
  require 'barcode1dtools/postnet'
131
+ require 'barcode1dtools/plessey'
132
+ require 'barcode1dtools/msi'
@@ -0,0 +1,262 @@
1
+ #--
2
+ # Copyright 2012 Michael Chaney Consulting Corporation
3
+ #
4
+ # Released under the terms of the MIT License or the GNU
5
+ # General Public License, v. 2
6
+ #++
7
+
8
+ module Barcode1DTools
9
+
10
+ # Barcode1DTools::MSI - Create and decode bar patterns for
11
+ # MSI. The value encoded is a string which may contain the
12
+ # digits 0-9.
13
+ #
14
+ # There are four possible check digit calculations, and you
15
+ # may use the option :check_digit => 'x' to choose which
16
+ # one to use. "x" may be one of "mod 10", "mod 11",
17
+ # "mod 1010", or "mod 1110". The default is "mod 10".
18
+ # For a mod 11 check digit, you may use :check_style =>
19
+ # 'ibm' or 'ncr'.
20
+ #
21
+ # MSI is a terrible symbology in modern terms and should
22
+ # not be used in any new applications.
23
+ #
24
+ # val = "2898289238"
25
+ # bc = Barcode1DTools::MSI.new(val)
26
+ # pattern = bc.bars
27
+ # rle_pattern = bc.rle
28
+ # width = bc.width
29
+ #
30
+ # The object created is immutable.
31
+ #
32
+ # Barcode1DTools::MSI creates the patterns that you need to
33
+ # display MSI barcodes. It can also decode a simple w/n
34
+ # string.
35
+ #
36
+ # MSI characters consist of 4 bars and 4 spaces. The
37
+ # representation is simply binary where a binary "0" is
38
+ # represented as a narrow bar followed by a wide space and
39
+ # a binary "1" is a wide bar followed by a narrow space.
40
+ # The bits are ordered descending, so 9 is 1001 binary,
41
+ # "wn nw nw wn" in w/n format.
42
+ #
43
+ # There are three formats for the returned pattern:
44
+ #
45
+ # bars - 1s and 0s specifying black lines and white spaces. Actual
46
+ # characters can be changed from "1" and 0" with options
47
+ # :line_character and :space_character.
48
+ #
49
+ # rle - Run-length-encoded version of the pattern. The first
50
+ # number is always a black line, with subsequent digits
51
+ # alternating between spaces and lines. The digits specify
52
+ # the width of each line or space.
53
+ #
54
+ # wn - The native format for this barcode type. The string
55
+ # consists of a series of "w" and "n" characters. The first
56
+ # item is always a black line, with subsequent characters
57
+ # alternating between spaces and lines. A "wide" item
58
+ # is twice the width of a "narrow" item.
59
+ #
60
+ # The "width" method will tell you the total end-to-end width, in
61
+ # units, of the entire barcode.
62
+ #
63
+ #== Rendering
64
+ #
65
+ # The author is aware of no standards for display.
66
+
67
+ class MSI < Barcode1D
68
+
69
+ # Character sequence - 0-based offset in this string is character
70
+ # number
71
+ CHAR_SEQUENCE = "0123456789"
72
+
73
+ # Patterns for making bar codes
74
+ PATTERNS = {
75
+ '0'=> {'val'=>0 ,'wn'=>'nwnwnwnw'},
76
+ '1'=> {'val'=>1 ,'wn'=>'nwnwnwwn'},
77
+ '2'=> {'val'=>2 ,'wn'=>'nwnwwnnw'},
78
+ '3'=> {'val'=>3 ,'wn'=>'nwnwwnwn'},
79
+ '4'=> {'val'=>4 ,'wn'=>'nwwnnwnw'},
80
+ '5'=> {'val'=>5 ,'wn'=>'nwwnnwwn'},
81
+ '6'=> {'val'=>6 ,'wn'=>'nwwnwnnw'},
82
+ '7'=> {'val'=>7 ,'wn'=>'nwwnwnwn'},
83
+ '8'=> {'val'=>8 ,'wn'=>'wnnwnwnw'},
84
+ '9'=> {'val'=>9 ,'wn'=>'wnnwnwwn'}
85
+ }
86
+
87
+ GUARD_PATTERN_LEFT_WN = 'wn'
88
+ GUARD_PATTERN_RIGHT_WN = 'nwn'
89
+
90
+ DEFAULT_OPTIONS = {
91
+ :line_character => '1',
92
+ :space_character => '0',
93
+ :w_character => 'w',
94
+ :n_character => 'n',
95
+ :wn_ratio => '2',
96
+ :check_digit => 'mod 10',
97
+ :check_style => 'ibm'
98
+ }
99
+
100
+ class << self
101
+ # MSI can encode digits
102
+ def can_encode?(value)
103
+ value.to_s =~ /\A\d+\z/
104
+ end
105
+
106
+ def generate_check_digit_for(value, options = {})
107
+ if options[:check_digit] == 'mod 10'
108
+ generate_mod10_check_digit_for(value).to_s
109
+ elsif options[:check_digit] == 'mod 11'
110
+ generate_mod11_check_digit_for(value, options[:check_style]).to_s
111
+ elsif options[:check_digit] == 'mod 1010'
112
+ mod10 = generate_mod10_check_digit_for(value)
113
+ mod10_2 = generate_mod10_check_digit_for(value + mod10.to_s)
114
+ "#{mod10}#{mod10_2}"
115
+ elsif options[:check_digit] == 'mod 1110'
116
+ mod11 = generate_mod11_check_digit_for(value, options[:check_style])
117
+ mod10_2 = generate_mod10_check_digit_for(value + mod11.to_s)
118
+ "#{mod11}#{mod10_2}"
119
+ end
120
+ end
121
+
122
+ def validate_check_digit_for(value, options = {})
123
+ payload, check_digits = split_payload_and_check_digits(value, options)
124
+ self.generate_check_digit_for(payload, options) == check_digits
125
+ end
126
+
127
+ def split_payload_and_check_digits(value, options = {})
128
+ if options[:check_digit] == 'mod 1010' || options[:check_digit] == 'mod 1110'
129
+ md = value.to_s.match(/\A(.*?)(..)\z/)
130
+ else
131
+ md = value.to_s.match(/\A(.*?)(.)\z/)
132
+ end
133
+ [md[1], md[2]]
134
+ end
135
+
136
+ def generate_mod10_check_digit_for(value)
137
+ value = value.to_s
138
+ valarr = value.scan(/\d\d?/)
139
+ if value.size.odd?
140
+ odd = valarr.collect { |c| c[0,1] }
141
+ even = valarr.collect { |c| c[1,1] }
142
+ else
143
+ odd = valarr.collect { |c| c[1,1] }
144
+ even = valarr.collect { |c| c[0,1] }
145
+ end
146
+ odd = (odd.join.to_i * 2).to_s.split('').inject(0) { |a,c| a + c.to_i }
147
+ even = even.inject(0) { |a,c| a + c.to_i }
148
+ (10 - ((odd + even) % 10)) % 10
149
+ end
150
+
151
+ def generate_mod11_check_digit_for(value, style)
152
+ max = (style == 'ncr' ? 9 : 7)
153
+ value = value.to_s
154
+ weight = 1
155
+ sum = value.split('').reverse.inject(0) { |a,c| weight = (weight == max ? 2 : weight + 1); a + weight * c.to_i }
156
+ (11 - (sum % 11)) % 11
157
+ end
158
+
159
+ # Decode a string in rle format. This will return a MSI
160
+ # object.
161
+ def decode(str, options = {})
162
+ if str =~ /[^1-3]/ && str =~ /[^wn]/
163
+ raise UnencodableCharactersError, "Pattern must be rle or wn"
164
+ end
165
+
166
+ # ensure a wn string
167
+ if str =~ /[1-3]/
168
+ str = str.tr('123','nww')
169
+ end
170
+
171
+ if str.reverse =~ /\A#{GUARD_PATTERN_LEFT_WN}.*?#{GUARD_PATTERN_RIGHT_WN}\z/
172
+ str.reverse!
173
+ end
174
+
175
+ unless str =~ /\A#{GUARD_PATTERN_LEFT_WN}(.*?)#{GUARD_PATTERN_RIGHT_WN}\z/
176
+ raise UnencodableCharactersError, "Start/stop pattern is not detected."
177
+ end
178
+
179
+ wn_pattern = $1
180
+
181
+ # Each pattern is 4 bars and 4 spaces, with a space between.
182
+ unless wn_pattern.size % 8 == 0
183
+ raise UnencodableCharactersError, "Wrong number of bars."
184
+ end
185
+
186
+ decoded_string = ''
187
+
188
+ wn_pattern.scan(/.{8}/).each do |chunk|
189
+
190
+ found = false
191
+
192
+ PATTERNS.each do |char,hsh|
193
+ if chunk == hsh['wn']
194
+ decoded_string += char
195
+ found = true
196
+ break;
197
+ end
198
+ end
199
+
200
+ raise UndecodableCharactersError, "Invalid sequence: #{chunk}" unless found
201
+
202
+ end
203
+
204
+ MSI.new(decoded_string, options)
205
+ end
206
+
207
+ end
208
+
209
+ # Options are :line_character, :space_character, :w_character,
210
+ # :n_character, :checksum_included, and :skip_checksum.
211
+ def initialize(value, options = {})
212
+
213
+ @options = DEFAULT_OPTIONS.merge(options)
214
+
215
+ # Can we encode this value?
216
+ raise UnencodableCharactersError unless self.class.can_encode?(value)
217
+
218
+ if @options[:skip_checksum]
219
+ @encoded_string = value.to_s
220
+ @value = value.to_s
221
+ @check_digit = nil
222
+ elsif @options[:checksum_included]
223
+ raise ChecksumError unless self.class.validate_check_digit_for(value, options)
224
+ @encoded_string = value.to_s
225
+ @value, @check_digit = self.class.split_payload_and_check_digits(value, options)
226
+ else
227
+ @value = value.to_s
228
+ @check_digit = self.class.generate_check_digit_for(@value, options)
229
+ @encoded_string = "#{@value}#{@check_digit}"
230
+ end
231
+ end
232
+
233
+ # Returns a string of "w" or "n" ("wide" and "narrow")
234
+ def wn
235
+ @wn ||= wn_str.tr('wn', @options[:w_character].to_s + @options[:n_character].to_s)
236
+ end
237
+
238
+ # returns a run-length-encoded string representation
239
+ def rle
240
+ @rle ||= self.class.wn_to_rle(self.wn, @options)
241
+ end
242
+
243
+ # returns 1s and 0s (for "black" and "white")
244
+ def bars
245
+ @bars ||= self.class.rle_to_bars(self.rle, @options)
246
+ end
247
+
248
+ # returns the total unit width of the bar code
249
+ def width
250
+ @width ||= rle.split('').inject(0) { |a,c| a + c.to_i }
251
+ end
252
+
253
+ private
254
+
255
+ # Creates the actual w/n pattern. Note that there is a narrow space
256
+ # between each character.
257
+ def wn_str
258
+ @wn_str ||= GUARD_PATTERN_LEFT_WN + @encoded_string.split('').collect { |c| PATTERNS[c]['wn'] }.join + GUARD_PATTERN_RIGHT_WN
259
+ end
260
+
261
+ end
262
+ end
@@ -0,0 +1,208 @@
1
+ #--
2
+ # Copyright 2012 Michael Chaney Consulting Corporation
3
+ #
4
+ # Released under the terms of the MIT License or the GNU
5
+ # General Public License, v. 2
6
+ #++
7
+
8
+ module Barcode1DTools
9
+
10
+ # Barcode1DTools::Plessey - Create and decode bar patterns for
11
+ # Plessey. The value encoded is a string which may contain the
12
+ # digits 0-9 and the letters A-F (0-15 hexadecimal).
13
+ #
14
+ # According to Wikipedia, a Plessey code should contain a two
15
+ # digit CRC8 checksum. This code does not provide checksum
16
+ # generation or validation.
17
+ #
18
+ # Plessey is a terrible symbology in modern terms and should
19
+ # not be used in any new applications.
20
+ #
21
+ # val = "2898289238AF"
22
+ # bc = Barcode1DTools::Plessey.new(val)
23
+ # pattern = bc.bars
24
+ # rle_pattern = bc.rle
25
+ # width = bc.width
26
+ #
27
+ # The object created is immutable.
28
+ #
29
+ # Barcode1DTools::Plessey creates the patterns that you need to
30
+ # display Plessey barcodes. It can also decode a simple w/n
31
+ # string.
32
+ #
33
+ # Plessey characters consist of 4 bars and 4 spaces. The
34
+ # representation is simply binary where a binary "0" is
35
+ # represented as a narrow bar followed by a wide space and
36
+ # a binary "1" is a wide bar followed by a narrow space.
37
+ # The bits are ordered ascending, so 9 is 1001 binary,
38
+ # "wn nw nw wn" in w/n format.
39
+ #
40
+ # There are three formats for the returned pattern:
41
+ #
42
+ # bars - 1s and 0s specifying black lines and white spaces. Actual
43
+ # characters can be changed from "1" and 0" with options
44
+ # :line_character and :space_character.
45
+ #
46
+ # rle - Run-length-encoded version of the pattern. The first
47
+ # number is always a black line, with subsequent digits
48
+ # alternating between spaces and lines. The digits specify
49
+ # the width of each line or space.
50
+ #
51
+ # wn - The native format for this barcode type. The string
52
+ # consists of a series of "w" and "n" characters. The first
53
+ # item is always a black line, with subsequent characters
54
+ # alternating between spaces and lines. A "wide" item
55
+ # is twice the width of a "narrow" item.
56
+ #
57
+ # The "width" method will tell you the total end-to-end width, in
58
+ # units, of the entire barcode.
59
+ #
60
+ #== Rendering
61
+ #
62
+ # The author is aware of no standards for display.
63
+
64
+ class Plessey < Barcode1D
65
+
66
+ # Character sequence - 0-based offset in this string is character
67
+ # number
68
+ CHAR_SEQUENCE = "0123456789ABCDEF"
69
+
70
+ # Patterns for making bar codes
71
+ PATTERNS = {
72
+ '0'=> {'val'=>0 ,'wn'=>'nwnwnwnw'},
73
+ '1'=> {'val'=>1 ,'wn'=>'wnnwnwnw'},
74
+ '2'=> {'val'=>2 ,'wn'=>'nwwnnwnw'},
75
+ '3'=> {'val'=>3 ,'wn'=>'wnwnnwnw'},
76
+ '4'=> {'val'=>4 ,'wn'=>'nwnwwnnw'},
77
+ '5'=> {'val'=>5 ,'wn'=>'wnnwwnnw'},
78
+ '6'=> {'val'=>6 ,'wn'=>'nwwnwnnw'},
79
+ '7'=> {'val'=>7 ,'wn'=>'wnwnwnnw'},
80
+ '8'=> {'val'=>8 ,'wn'=>'nwnwnwwn'},
81
+ '9'=> {'val'=>9 ,'wn'=>'wnnwnwwn'},
82
+ 'A'=> {'val'=>10 ,'wn'=>'nwwnnwwn'},
83
+ 'B'=> {'val'=>11 ,'wn'=>'wnwnnwwn'},
84
+ 'C'=> {'val'=>12 ,'wn'=>'nwnwwnwn'},
85
+ 'D'=> {'val'=>13 ,'wn'=>'wnnwwnwn'},
86
+ 'E'=> {'val'=>14 ,'wn'=>'nwwnwnwn'},
87
+ 'F'=> {'val'=>15 ,'wn'=>'wnwnwnwn'}
88
+ }
89
+
90
+ GUARD_PATTERN_LEFT_WN = 'wnwnnwwn'
91
+ GUARD_PATTERN_RIGHT_WN = 'wnwnnwnw'
92
+
93
+ DEFAULT_OPTIONS = {
94
+ :line_character => '1',
95
+ :space_character => '0',
96
+ :w_character => 'w',
97
+ :n_character => 'n',
98
+ :wn_ratio => '2'
99
+ }
100
+
101
+ class << self
102
+ # Plessey can encode digits and A-F.
103
+ def can_encode?(value)
104
+ value.to_s =~ /\A[0-9A-F]+\z/
105
+ end
106
+
107
+ def generate_check_digit_for(value)
108
+ raise NotImplementedError
109
+ end
110
+
111
+ def validate_check_digit_for(value)
112
+ raise NotImplementedError
113
+ end
114
+
115
+ # Decode a string in rle format. This will return a Plessey
116
+ # object.
117
+ def decode(str, options = {})
118
+ if str =~ /[^1-3]/ && str =~ /[^wn]/
119
+ raise UnencodableCharactersError, "Pattern must be rle or wn"
120
+ end
121
+
122
+ # ensure a wn string
123
+ if str =~ /[1-3]/
124
+ str = str.tr('123','nww')
125
+ end
126
+
127
+ if str.reverse =~ /\A#{GUARD_PATTERN_LEFT_WN}.*?#{GUARD_PATTERN_RIGHT_WN}\z/
128
+ str.reverse!
129
+ end
130
+
131
+ unless str =~ /\A#{GUARD_PATTERN_LEFT_WN}(.*?)#{GUARD_PATTERN_RIGHT_WN}\z/
132
+ raise UnencodableCharactersError, "Start/stop pattern is not detected."
133
+ end
134
+
135
+ wn_pattern = $1
136
+
137
+ # Each pattern is 4 bars and 4 spaces, with a space between.
138
+ unless wn_pattern.size % 8 == 0
139
+ raise UnencodableCharactersError, "Wrong number of bars."
140
+ end
141
+
142
+ decoded_string = ''
143
+
144
+ wn_pattern.scan(/.{8}/).each do |chunk|
145
+
146
+ found = false
147
+
148
+ PATTERNS.each do |char,hsh|
149
+ if chunk == hsh['wn']
150
+ decoded_string += char
151
+ found = true
152
+ break;
153
+ end
154
+ end
155
+
156
+ raise UndecodableCharactersError, "Invalid sequence: #{chunk}" unless found
157
+
158
+ end
159
+
160
+ Plessey.new(decoded_string, options)
161
+ end
162
+
163
+ end
164
+
165
+ # Options are :line_character, :space_character, :w_character,
166
+ # :n_character, :checksum_included, and :skip_checksum.
167
+ def initialize(value, options = {})
168
+
169
+ @options = DEFAULT_OPTIONS.merge(options)
170
+
171
+ # Can we encode this value?
172
+ raise UnencodableCharactersError unless self.class.can_encode?(value)
173
+
174
+ @value = value.to_s
175
+ @encoded_string = value.to_s
176
+ @check_digit = nil
177
+ end
178
+
179
+ # Returns a string of "w" or "n" ("wide" and "narrow")
180
+ def wn
181
+ @wn ||= wn_str.tr('wn', @options[:w_character].to_s + @options[:n_character].to_s)
182
+ end
183
+
184
+ # returns a run-length-encoded string representation
185
+ def rle
186
+ @rle ||= self.class.wn_to_rle(self.wn, @options)
187
+ end
188
+
189
+ # returns 1s and 0s (for "black" and "white")
190
+ def bars
191
+ @bars ||= self.class.rle_to_bars(self.rle, @options)
192
+ end
193
+
194
+ # returns the total unit width of the bar code
195
+ def width
196
+ @width ||= rle.split('').inject(0) { |a,c| a + c.to_i }
197
+ end
198
+
199
+ private
200
+
201
+ # Creates the actual w/n pattern. Note that there is a narrow space
202
+ # between each character.
203
+ def wn_str
204
+ @wn_str ||= GUARD_PATTERN_LEFT_WN + @encoded_string.split('').collect { |c| PATTERNS[c]['wn'] }.join + GUARD_PATTERN_RIGHT_WN
205
+ end
206
+
207
+ end
208
+ end
@@ -0,0 +1,79 @@
1
+ #--
2
+ # Copyright 2012 Michael Chaney Consulting Corporation
3
+ #
4
+ # Released under the terms of the MIT License or the GNU
5
+ # General Public License, v. 2
6
+ #++
7
+
8
+ require 'test/unit'
9
+ require 'barcode1dtools'
10
+
11
+ class Barcode1DToolsMSITest < Test::Unit::TestCase
12
+ def setup
13
+ end
14
+
15
+ def teardown
16
+ end
17
+
18
+ # Creates a random number from 1 to 10 digits long
19
+ def random_msi_value(len)
20
+ (1..1+rand(len)).collect { "0123456789"[rand(11),1] }.join
21
+ end
22
+
23
+ def test_checksum_generation
24
+ assert_equal '4', Barcode1DTools::MSI.generate_check_digit_for('1234567', :check_digit => 'mod 10')
25
+ end
26
+
27
+ def test_checksum_validation
28
+ assert Barcode1DTools::MSI.validate_check_digit_for('12345674', :check_digit => 'mod 10')
29
+ end
30
+
31
+ def test_attr_readers
32
+ msi = Barcode1DTools::MSI.new('1234567', :check_digit => 'mod 10', :checksum_included => false)
33
+ assert_equal '4', msi.check_digit
34
+ assert_equal '1234567', msi.value
35
+ assert_equal '12345674', msi.encoded_string
36
+ end
37
+
38
+ def test_checksum_error
39
+ # proper checksum is 5
40
+ assert_raise(Barcode1DTools::ChecksumError) { Barcode1DTools::MSI.new('12345671', :check_digit => 'mod 10', :checksum_included => true) }
41
+ end
42
+
43
+ def test_skip_checksum
44
+ msi = Barcode1DTools::MSI.new('12345', :skip_checksum => true)
45
+ assert_nil msi.check_digit
46
+ assert_equal '12345', msi.value
47
+ assert_equal '12345', msi.encoded_string
48
+ end
49
+
50
+ def test_bad_character_errors
51
+ # Characters that cannot be encoded
52
+ assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::MSI.new('thisisnotgood', :checksum_included => false) }
53
+ end
54
+
55
+ # Only need to test wn, as bars and rle are based on wn
56
+ def test_barcode_generation
57
+ msi = Barcode1DTools::MSI.new('12345674', :skip_checksum => true, :line_character => '#', :space_character => ' ')
58
+ assert_equal "## # # # ## # # ## # # # ## ## # ## # # # ## # ## # ## ## # # ## ## ## # ## # # # #", msi.bars
59
+ end
60
+
61
+ def test_decode_error
62
+ assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::MSI.decode('x') }
63
+ assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::MSI.decode('x'*60) }
64
+ # proper start & stop, but crap in middle
65
+ assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::MSI.decode('nnwwnnnnnnnnnnnwwn') }
66
+ # wrong start/stop
67
+ assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::MSI.decode('nwwnwnwnwnwnwnw') }
68
+ end
69
+
70
+ def test_decoding
71
+ random_msi_num=random_msi_value(10)
72
+ msi = Barcode1DTools::MSI.new(random_msi_num, :skip_checksum => true)
73
+ msi2 = Barcode1DTools::MSI.decode(msi.wn)
74
+ assert_equal msi.value, msi2.value
75
+ # Should also work in reverse
76
+ msi4 = Barcode1DTools::MSI.decode(msi.wn.reverse)
77
+ assert_equal msi.value, msi4.value
78
+ end
79
+ end
@@ -0,0 +1,53 @@
1
+ #--
2
+ # Copyright 2012 Michael Chaney Consulting Corporation
3
+ #
4
+ # Released under the terms of the MIT License or the GNU
5
+ # General Public License, v. 2
6
+ #++
7
+
8
+ require 'test/unit'
9
+ require 'barcode1dtools'
10
+
11
+ class Barcode1DToolsPlesseyTest < Test::Unit::TestCase
12
+ def setup
13
+ end
14
+
15
+ def teardown
16
+ end
17
+
18
+ # Creates a random number from 1 to 10 digits long
19
+ def random_plessey_value(len)
20
+ (1..1+rand(len)).collect { "0123456789"[rand(11),1] }.join
21
+ end
22
+
23
+ def test_attr_readers
24
+ plessey = Barcode1DTools::Plessey.new('12345')
25
+ assert_nil plessey.check_digit
26
+ assert_equal '12345', plessey.value
27
+ assert_equal '12345', plessey.encoded_string
28
+ end
29
+
30
+ def test_bad_character_errors
31
+ # Characters that cannot be encoded
32
+ assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::Plessey.new('thisisnotgood', :checksum_included => false) }
33
+ end
34
+
35
+ def test_decode_error
36
+ assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::Plessey.decode('x') }
37
+ assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::Plessey.decode('x'*60) }
38
+ # proper start & stop, but crap in middle
39
+ assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::Plessey.decode('nnwwnnnnnnnnnnnwwn') }
40
+ # wrong start/stop
41
+ assert_raise(Barcode1DTools::UnencodableCharactersError) { Barcode1DTools::Plessey.decode('nwwnwnwnwnwnwnw') }
42
+ end
43
+
44
+ def test_decoding
45
+ random_plessey_num=random_plessey_value(10)
46
+ plessey = Barcode1DTools::Plessey.new(random_plessey_num)
47
+ plessey2 = Barcode1DTools::Plessey.decode(plessey.wn)
48
+ assert_equal plessey.value, plessey2.value
49
+ # Should also work in reverse
50
+ plessey4 = Barcode1DTools::Plessey.decode(plessey.wn.reverse)
51
+ assert_equal plessey.value, plessey4.value
52
+ end
53
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: barcode1dtools
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 39
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 9
9
- - 7
9
+ - 8
10
10
  - 0
11
- version: 0.9.7.0
11
+ version: 0.9.8.0
12
12
  platform: ruby
13
13
  authors:
14
14
  - Michael Chaney
@@ -23,13 +23,13 @@ dependencies: []
23
23
  description: "\t Barcode1D is a small library for handling many kinds of\n\
24
24
  \t 1-dimensional barcodes. Currently implemented are Code 3 of 9, Code\n\
25
25
  \t 93, Code 11, Codabar, Interleaved 2 of 5, COOP 2 of 5, Matrix 2 of\n\
26
- \t 5, Industrial 2 of 5, IATA 2 of 5, PostNet, EAN-13, EAN-8, UPC-A,\n\
27
- \t UPC-E, UPC Supplemental 2, and UPC Supplemental 5. Patterns are\n\
28
- \t created in either a simple format of bars and spaces or as a\n\
29
- \t run-length encoded string. This only generates and decodes the\n\
30
- \t patterns; actual display or reading from a device must be\n\
31
- \t implemented by the programmer. More symbologies will be added as\n\
32
- \t time permits.\n"
26
+ \t 5, Industrial 2 of 5, IATA 2 of 5, PostNet, Plessey, MSI (Modified\n\
27
+ \t Plessey), EAN-13, EAN-8, UPC-A, UPC-E, UPC Supplemental 2, and UPC\n\
28
+ \t Supplemental 5. Patterns are created in either a simple format of\n\
29
+ \t bars and spaces or as a run-length encoded string. This only\n\
30
+ \t generates and decodes the patterns; actual display or reading from a\n\
31
+ \t device must be implemented by the programmer. More symbologies will\n\
32
+ \t be added as time permits.\n"
33
33
  email: mdchaney@michaelchaney.com
34
34
  executables: []
35
35
 
@@ -49,6 +49,8 @@ files:
49
49
  - lib/barcode1dtools/industrial2of5.rb
50
50
  - lib/barcode1dtools/interleaved2of5.rb
51
51
  - lib/barcode1dtools/matrix2of5.rb
52
+ - lib/barcode1dtools/msi.rb
53
+ - lib/barcode1dtools/plessey.rb
52
54
  - lib/barcode1dtools/postnet.rb
53
55
  - lib/barcode1dtools/upc_a.rb
54
56
  - lib/barcode1dtools/upc_e.rb
@@ -68,6 +70,8 @@ files:
68
70
  - test/test_barcode1diata2of5.rb
69
71
  - test/test_barcode1dindustrial2of5.rb
70
72
  - test/test_barcode1dmatrix2of5.rb
73
+ - test/test_barcode1dmsi.rb
74
+ - test/test_barcode1dplessey.rb
71
75
  - test/test_barcode1dpostnet.rb
72
76
  - test/test_barcode1dupca.rb
73
77
  - test/test_barcode1dupce.rb
@@ -123,6 +127,8 @@ test_files:
123
127
  - test/test_barcode1diata2of5.rb
124
128
  - test/test_barcode1dindustrial2of5.rb
125
129
  - test/test_barcode1dmatrix2of5.rb
130
+ - test/test_barcode1dmsi.rb
131
+ - test/test_barcode1dplessey.rb
126
132
  - test/test_barcode1dpostnet.rb
127
133
  - test/test_barcode1dupca.rb
128
134
  - test/test_barcode1dupce.rb