barby 0.1

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.
data/README ADDED
@@ -0,0 +1,29 @@
1
+ Barby is a Ruby barcode generator. It does not depend on other libraries
2
+ (for the core functionality) and is easily extentable.
3
+
4
+ The barcode objects are separated from the process of generating graphical
5
+ (or other) representations. A barcode's only responsibility is to provide
6
+ a string representation consisting of 1s and 0s representing bars and spaces.
7
+ This string can then be used to generate (for example) an image with the
8
+ RMagickOutputter, or an ASCII string such as the one below.
9
+
10
+ See Barby::Barcode and Barby::Outputter for more information.
11
+
12
+ require 'barby'
13
+ require 'barby/outputter/ascii_outputter'
14
+
15
+ barcode = Barby::Code128B.new('BARBY')
16
+
17
+ puts barcode.to_ascii
18
+
19
+ ## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ##
20
+ ## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ##
21
+ ## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ##
22
+ ## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ##
23
+ ## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ##
24
+ ## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ##
25
+ ## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ##
26
+ ## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ##
27
+ ## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ##
28
+ ## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ##
29
+ B A R B Y
@@ -0,0 +1,11 @@
1
+ require 'barby/version'
2
+
3
+ require 'barby/barcode'
4
+ require 'barby/barcode/code_128'
5
+ require 'barby/barcode/gs1_128'
6
+ require 'barby/barcode/code_39'
7
+ require 'barby/barcode/ean_13'
8
+ require 'barby/barcode/ean_8'
9
+ require 'barby/barcode/bookland'
10
+
11
+ require 'barby/outputter'
@@ -0,0 +1,95 @@
1
+ module Barby
2
+
3
+
4
+ #The base class for all barcodes. It includes some method_missing magic
5
+ #that is used to find registered outputters.
6
+ #
7
+ #The only interface requirement of a barcode class is that is has an encoding
8
+ #method that returns a string consisting of 1s and 0s representing the barcode's
9
+ #"black" and "white" parts. One digit is the width of the "X dimension"; that is,
10
+ #"101100" represents a single-width bar followed by a single-width space, then
11
+ #a bar and a space twice that width.
12
+ #
13
+ #Example implementation:
14
+ #
15
+ # class StaticBarcode < Barby::Barcode1D
16
+ # def encoding
17
+ # '101100111000111100001'
18
+ # end
19
+ # end
20
+ #
21
+ # require 'barby/outputter/ascii_outputter'
22
+ # puts StaticBarcode.new.to_ascii(:height => 3)
23
+ #
24
+ # # ## ### #### #
25
+ # # ## ### #### #
26
+ # # ## ### #### #
27
+ class Barcode
28
+
29
+
30
+ #Every barcode must have an encoding method. This method returns
31
+ #a string containing a series of 1 and 0, representing bars and
32
+ #spaces. One digit is the width of one "module" or X dimension.
33
+ def encoding
34
+ raise NotImplementedError, 'Every barcode should implement this method'
35
+ end
36
+
37
+
38
+ #Is this barcode valid?
39
+ def valid?
40
+ false
41
+ end
42
+
43
+
44
+ def method_missing(name, *args, &b)#:nodoc:
45
+ #See if an outputter has registered this method
46
+ if self.class.outputters.include?(name)
47
+ klass, method_name = self.class.outputters[name]
48
+ klass.new(self).send(method_name, *args, &b)
49
+ else
50
+ super
51
+ end
52
+ end
53
+
54
+
55
+ #Returns an instantiated outputter for +name+ if any outputter
56
+ #has registered that name
57
+ def outputter_for(name, *a, &b)
58
+ outputter_class_for(name).new(self, *a, &b)
59
+ end
60
+
61
+ #Get the outputter class object for +name+
62
+ def outputter_class_for(name)
63
+ self.class.outputters[name].first
64
+ end
65
+
66
+
67
+ class << self
68
+
69
+ def outputters
70
+ @@outputters ||= {}
71
+ end
72
+
73
+ #Registers an outputter with +name+ so that a call to
74
+ #+name+ on a Barcode instance will be delegated to this outputter
75
+ def register_outputter(name, klass, method_name)
76
+ outputters[name] = [klass, method_name]
77
+ end
78
+
79
+ end
80
+
81
+ end
82
+
83
+
84
+ #Most barcodes are one-dimensional. They have bars.
85
+ class Barcode1D < Barcode
86
+ end
87
+
88
+ #There is currently only support for one-dimensional barcodes,
89
+ #but in the future it should also be possible to support barcodes
90
+ #with two dimensions.
91
+ class Barcode2D < Barcode
92
+ end
93
+
94
+
95
+ end
@@ -0,0 +1,37 @@
1
+ require 'barby/barcode/ean_13'
2
+
3
+ module Barby
4
+
5
+ #Bookland barcodes are EAN-13 barcodes with number system
6
+ #978 (hence "Bookland"). The data they encode is an ISBN
7
+ #with its check digit removed. This is a convenience class
8
+ #that takes an ISBN no instead of "pure" EAN-13 data.
9
+ class Bookland < EAN13
10
+
11
+ BOOKLAND_NUMBER_SYSTEM = '978'
12
+
13
+ attr_accessor :isbn
14
+
15
+ def initialize(isbn)
16
+ self.isbn = isbn
17
+ raise ArgumentError, 'data not valid' unless valid?
18
+ end
19
+
20
+ def data
21
+ BOOKLAND_NUMBER_SYSTEM+isbn_only
22
+ end
23
+
24
+ #Removes any non-digit characters, number system and check digit
25
+ #from ISBN, so "978-82-92526-14-9" would result in "829252614"
26
+ def isbn_only
27
+ s = isbn.gsub(/[^0-9]/, '')
28
+ if s.size > 10#Includes number system
29
+ s[3,9]
30
+ else#No number system, may include check digit
31
+ s[0,9]
32
+ end
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,361 @@
1
+ require 'barby/barcode'
2
+
3
+ module Barby
4
+
5
+
6
+ #Code 128 barcodes
7
+ class Code128 < Barcode1D
8
+
9
+ ENCODINGS = {
10
+ 0 => "11011001100", 1 => "11001101100", 2 => "11001100110",
11
+ 3 => "10010011000", 4 => "10010001100", 5 => "10001001100",
12
+ 6 => "10011001000", 7 => "10011000100", 8 => "10001100100",
13
+ 9 => "11001001000", 10 => "11001000100", 11 => "11000100100",
14
+ 12 => "10110011100", 13 => "10011011100", 14 => "10011001110",
15
+ 15 => "10111001100", 16 => "10011101100", 17 => "10011100110",
16
+ 18 => "11001110010", 19 => "11001011100", 20 => "11001001110",
17
+ 21 => "11011100100", 22 => "11001110100", 23 => "11101101110",
18
+ 24 => "11101001100", 25 => "11100101100", 26 => "11100100110",
19
+ 27 => "11101100100", 28 => "11100110100", 29 => "11100110010",
20
+ 30 => "11011011000", 31 => "11011000110", 32 => "11000110110",
21
+ 33 => "10100011000", 34 => "10001011000", 35 => "10001000110",
22
+ 36 => "10110001000", 37 => "10001101000", 38 => "10001100010",
23
+ 39 => "11010001000", 40 => "11000101000", 41 => "11000100010",
24
+ 42 => "10110111000", 43 => "10110001110", 44 => "10001101110",
25
+ 45 => "10111011000", 46 => "10111000110", 47 => "10001110110",
26
+ 48 => "11101110110", 49 => "11010001110", 50 => "11000101110",
27
+ 51 => "11011101000", 52 => "11011100010", 53 => "11011101110",
28
+ 54 => "11101011000", 55 => "11101000110", 56 => "11100010110",
29
+ 57 => "11101101000", 58 => "11101100010", 59 => "11100011010",
30
+ 60 => "11101111010", 61 => "11001000010", 62 => "11110001010",
31
+ 63 => "10100110000", 64 => "10100001100", 65 => "10010110000",
32
+ 66 => "10010000110", 67 => "10000101100", 68 => "10000100110",
33
+ 69 => "10110010000", 70 => "10110000100", 71 => "10011010000",
34
+ 72 => "10011000010", 73 => "10000110100", 74 => "10000110010",
35
+ 75 => "11000010010", 76 => "11001010000", 77 => "11110111010",
36
+ 78 => "11000010100", 79 => "10001111010", 80 => "10100111100",
37
+ 81 => "10010111100", 82 => "10010011110", 83 => "10111100100",
38
+ 84 => "10011110100", 85 => "10011110010", 86 => "11110100100",
39
+ 87 => "11110010100", 88 => "11110010010", 89 => "11011011110",
40
+ 90 => "11011110110", 91 => "11110110110", 92 => "10101111000",
41
+ 93 => "10100011110", 94 => "10001011110", 95 => "10111101000",
42
+ 96 => "10111100010", 97 => "11110101000", 98 => "11110100010",
43
+ 99 => "10111011110", 100 => "10111101110", 101 => "11101011110",
44
+ 102 => "11110101110", 103 => "11010000100", 104 => "11010010000",
45
+ 105 => "11010011100"
46
+ }
47
+
48
+ VALUES = {
49
+ 'A' => {
50
+ 0 => "SP", 1 => "!", 2 => "\"",
51
+ 3 => "#", 4 => "$", 5 => "%",
52
+ 6 => "&", 7 => "'", 8 => "(",
53
+ 9 => ")", 10 => "*", 11 => "+",
54
+ 12 => ",", 13 => "-", 14 => ".",
55
+ 15 => "/", 16 => "0", 17 => "1",
56
+ 18 => "2", 19 => "3", 20 => "4",
57
+ 21 => "5", 22 => "6", 23 => "7",
58
+ 24 => "8", 25 => "9", 26 => ":",
59
+ 27 => ";", 28 => "<", 29 => "=",
60
+ 30 => ">", 31 => "?", 32 => "@",
61
+ 33 => "A", 34 => "B", 35 => "C",
62
+ 36 => "D", 37 => "E", 38 => "F",
63
+ 39 => "G", 40 => "H", 41 => "I",
64
+ 42 => "J", 43 => "K", 44 => "L",
65
+ 45 => "M", 46 => "N", 47 => "O",
66
+ 48 => "P", 49 => "Q", 50 => "R",
67
+ 51 => "S", 52 => "T", 53 => "U",
68
+ 54 => "V", 55 => "W", 56 => "X",
69
+ 57 => "Y", 58 => "Z", 59 => "[",
70
+ 60 => "\\", 61 => "]", 62 => "^",
71
+ 63 => "_", 64 => "\000", 65 => "\001",
72
+ 66 => "\002", 67 => "\003", 68 => "\004",
73
+ 69 => "\005", 70 => "\006", 71 => "\a",
74
+ 72 => "\b", 73 => "\t", 74 => "\n",
75
+ 75 => "\v", 76 => "\f", 77 => "\r",
76
+ 78 => "\016", 79 => "\017", 80 => "\020",
77
+ 81 => "\021", 82 => "\022", 83 => "\023",
78
+ 84 => "\024", 85 => "\025", 86 => "\026",
79
+ 87 => "\027", 88 => "\030", 89 => "\031",
80
+ 90 => "\032", 91 => "\e", 92 => "\034",
81
+ 93 => "\035", 94 => "\036", 95 => "\037",
82
+ 96 => "\303", 97 => "\302", 98 => "SHIFT",
83
+ 99 => "\307", 100 => "\306", 101 => "\304",
84
+ 102 => "\301", 103 => "STARTA", 104 => "STARTB",
85
+ 105 => "STARTC"
86
+ }.invert,
87
+
88
+ 'B' => {
89
+ 0 => "SP", 1 => "!", 2 => "\"", 3 => "#", 4 => "$", 5 => "%",
90
+ 6 => "&", 7 => "'", 8 => "(", 9 => ")", 10 => "*", 11 => "+",
91
+ 12 => ",", 13 => "-", 14 => ".", 15 => "/", 16 => "0", 17 => "1",
92
+ 18 => "2", 19 => "3", 20 => "4", 21 => "5", 22 => "6", 23 => "7",
93
+ 24 => "8", 25 => "9", 26 => ":", 27 => ";", 28 => "<", 29 => "=",
94
+ 30 => ">", 31 => "?", 32 => "@", 33 => "A", 34 => "B", 35 => "C",
95
+ 36 => "D", 37 => "E", 38 => "F", 39 => "G", 40 => "H", 41 => "I",
96
+ 42 => "J", 43 => "K", 44 => "L", 45 => "M", 46 => "N", 47 => "O",
97
+ 48 => "P", 49 => "Q", 50 => "R", 51 => "S", 52 => "T", 53 => "U",
98
+ 54 => "V", 55 => "W", 56 => "X", 57 => "Y", 58 => "Z", 59 => "[",
99
+ 60 => "\\", 61 => "]", 62 => "^", 63 => "_", 64 => "`", 65 => "a",
100
+ 66 => "b", 67 => "c", 68 => "d", 69 => "e", 70 => "f", 71 => "g",
101
+ 72 => "h", 73 => "i", 74 => "j", 75 => "k", 76 => "l", 77 => "m",
102
+ 78 => "n", 79 => "o", 80 => "p", 81 => "q", 82 => "r", 83 => "s",
103
+ 84 => "t", 85 => "u", 86 => "v", 87 => "w", 88 => "x", 89 => "y",
104
+ 90 => "z", 91 => "{", 92 => "|", 93 => "}", 94 => "~", 95 => "\177",
105
+ 96 => "\303", 97 => "\302", 98 => "SHIFT", 99 => "\307", 100 => "\304",
106
+ 101 => "\305", 102 => "\301", 103 => "STARTA", 104 => "STARTB",
107
+ 105 => "STARTC",
108
+ }.invert,
109
+
110
+ 'C' => {
111
+ 0 => "00", 1 => "01", 2 => "02", 3 => "03", 4 => "04", 5 => "05",
112
+ 6 => "06", 7 => "07", 8 => "08", 9 => "09", 10 => "10", 11 => "11",
113
+ 12 => "12", 13 => "13", 14 => "14", 15 => "15", 16 => "16", 17 => "17",
114
+ 18 => "18", 19 => "19", 20 => "20", 21 => "21", 22 => "22", 23 => "23",
115
+ 24 => "24", 25 => "25", 26 => "26", 27 => "27", 28 => "28", 29 => "29",
116
+ 30 => "30", 31 => "31", 32 => "32", 33 => "33", 34 => "34", 35 => "35",
117
+ 36 => "36", 37 => "37", 38 => "38", 39 => "39", 40 => "40", 41 => "41",
118
+ 42 => "42", 43 => "43", 44 => "44", 45 => "45", 46 => "46", 47 => "47",
119
+ 48 => "48", 49 => "49", 50 => "50", 51 => "51", 52 => "52", 53 => "53",
120
+ 54 => "54", 55 => "55", 56 => "56", 57 => "57", 58 => "58", 59 => "59",
121
+ 60 => "60", 61 => "61", 62 => "62", 63 => "63", 64 => "64", 65 => "65",
122
+ 66 => "66", 67 => "67", 68 => "68", 69 => "69", 70 => "70", 71 => "71",
123
+ 72 => "72", 73 => "73", 74 => "74", 75 => "75", 76 => "76", 77 => "77",
124
+ 78 => "78", 79 => "79", 80 => "80", 81 => "81", 82 => "82", 83 => "83",
125
+ 84 => "84", 85 => "85", 86 => "86", 87 => "87", 88 => "88", 89 => "89",
126
+ 90 => "90", 91 => "91", 92 => "92", 93 => "93", 94 => "94", 95 => "95",
127
+ 96 => "96", 97 => "97", 98 => "98", 99 => "99", 100 => "\306", 101 => "\305",
128
+ 102 => "\301", 103 => "STARTA", 104 => "STARTB", 105 => "STARTC"
129
+ }.invert
130
+ }
131
+
132
+ FNC1 = "\xc1"
133
+ FNC2 = "\xc2"
134
+ FNC3 = "\xc3"
135
+ FNC4 = "\xc4"
136
+ CODEA = "\xc5"
137
+ CODEB = "\xc6"
138
+ CODEC = "\xc7"
139
+
140
+ STOP = '11000111010'
141
+ TERMINATE = '11'
142
+
143
+ attr_reader :type
144
+
145
+
146
+ def initialize(data, type)
147
+ self.type = type
148
+ self.data = "#{data}"
149
+ raise ArgumentError, 'Data not valid' unless valid?
150
+ end
151
+
152
+
153
+ def type=(type)
154
+ type.upcase!
155
+ raise ArgumentError, 'type must be A, B or C' unless type =~ /^[ABC]$/
156
+ @type = type
157
+ end
158
+
159
+
160
+ def data
161
+ @data
162
+ end
163
+
164
+ #Set the data for this barcode. If the barcode changes
165
+ #character set, an extra will be created.
166
+ def data=(data)
167
+ data, *extra = data.split(/([#{CODEA+CODEB+CODEC}])/n)
168
+ @data = data
169
+ self.extra = extra.join unless extra.empty?
170
+ end
171
+
172
+ #An "extra" is present if the barcode changes character set. If
173
+ #a 128A barcode changes to C, the extra will be an instance of
174
+ #Code128C. Extras can themselves have an extra if the barcode
175
+ #changes character set again. It's like a linked list, and when
176
+ #there are no more extras, the barcode ends with that object.
177
+ #Most barcodes probably don't change charsets and don't have extras.
178
+ def extra
179
+ @extra
180
+ end
181
+
182
+ #Set the extra for this barcode. The argument is a string starting with the
183
+ #"change character set" symbol. The string may contain several character
184
+ #sets, in which case the extra will itself have an extra.
185
+ def extra=(extra)
186
+ raise ArgumentError, "Extra must begin with \\301, \\302 or \\303" unless extra =~ /^[#{CODEA+CODEB+CODEC}]/n
187
+ type = extra[/([#{CODEA+CODEB+CODEC}])/n, 1]
188
+ data = extra[/[#{CODEA+CODEB+CODEC}](.*)/n, 1]
189
+ @extra = class_for(type).new(data)
190
+ end
191
+
192
+ #Get an array of the individual characters for this barcode. Special
193
+ #characters like FNC1 will be present. Characters from extras are not
194
+ #present.
195
+ def characters
196
+ chars = data.split(//n)
197
+
198
+ if type == 'C'
199
+ result = []
200
+ count = 0
201
+ while count < chars.size
202
+ if chars[count] =~ /^\d$/
203
+ result << "#{chars[count]}#{chars[count+1]}"
204
+ count += 2
205
+ else
206
+ result << chars[count]
207
+ count += 1
208
+ end
209
+ end
210
+ result
211
+ else
212
+ chars
213
+ end
214
+ end
215
+
216
+ #Return the encoding of this barcode as a string of 1 and 0
217
+ def encoding
218
+ start_encoding+data_encoding+extra_encoding+checksum_encoding+stop_encoding
219
+ end
220
+
221
+ #Returns the encoding for the data part of this barcode, without any extras
222
+ def data_encoding
223
+ characters.map do |char|
224
+ encoding_for char
225
+ end.join
226
+ end
227
+
228
+ #Returns the data encoding of this barcode and extras.
229
+ def data_encoding_with_extra_encoding
230
+ data_encoding+extra_encoding
231
+ end
232
+
233
+ #Returns the data encoding of this barcode's extra and its
234
+ #extra until the barcode ends.
235
+ def extra_encoding
236
+ return '' unless extra
237
+ change_code_encoding_for(extra) + extra.data_encoding + extra.extra_encoding
238
+ end
239
+
240
+
241
+ #Calculate the checksum for the data in this barcode. The data includes
242
+ #data from extras.
243
+ def checksum
244
+ pos = 0
245
+ (numbers+extra_numbers).inject(start_num) do |sum,number|
246
+ pos += 1
247
+ sum + (number * pos)
248
+ end % 103
249
+ end
250
+
251
+ #Get the encoding for the checksum
252
+ def checksum_encoding
253
+ encodings[checksum]
254
+ end
255
+
256
+
257
+ #protected
258
+
259
+ #Returns the numeric values for the characters in the barcode in an array
260
+ def numbers
261
+ characters.map do |char|
262
+ values[char]
263
+ end
264
+ end
265
+
266
+ #Returns the numeric values for extras
267
+ def extra_numbers
268
+ return [] unless extra
269
+ [change_code_number_for(extra)] + extra.numbers + extra.extra_numbers
270
+ end
271
+
272
+ def encodings
273
+ ENCODINGS
274
+ end
275
+
276
+ #The start encoding starts the barcode
277
+ def stop_encoding
278
+ STOP+TERMINATE
279
+ end
280
+
281
+ #Find the encoding for the specified character for this barcode
282
+ def encoding_for(char)
283
+ encodings[values[char]]
284
+ end
285
+
286
+ #Find the numeric value for the character that changes the character
287
+ #set to the one represented in +barcode+
288
+ def change_code_number_for(barcode)
289
+ case barcode
290
+ when Code128A then values[CODEA]
291
+ when Code128B then values[CODEB]
292
+ when Code128C then values[CODEC]
293
+ end
294
+ end
295
+
296
+ #Find the encoding to change to the character set in +barcode+
297
+ def change_code_encoding_for(barcode)
298
+ encodings[change_code_number_for(barcode)]
299
+ end
300
+
301
+ def class_for(character)
302
+ case character
303
+ when 'A' then Code128A
304
+ when 'B' then Code128B
305
+ when 'C' then Code128C
306
+ when CODEA then Code128A
307
+ when CODEB then Code128B
308
+ when CODEC then Code128C
309
+ end
310
+ end
311
+
312
+ #Is the data in this barcode valid? Does a lookup of every character
313
+ #and checks if it exists in the character set.
314
+ def valid?
315
+ characters.all?{|c| values.include?(c) }
316
+ end
317
+
318
+ def values
319
+ VALUES[type]
320
+ end
321
+
322
+ def start_num
323
+ values["START#{type}"]
324
+ end
325
+
326
+ def start_encoding
327
+ encodings[start_num]
328
+ end
329
+
330
+
331
+ end
332
+
333
+
334
+ class Code128A < Code128
335
+
336
+ def initialize(data)
337
+ super(data, 'A')
338
+ end
339
+
340
+ end
341
+
342
+
343
+ class Code128B < Code128
344
+
345
+ def initialize(data)
346
+ super(data, 'B')
347
+ end
348
+
349
+ end
350
+
351
+
352
+ class Code128C < Code128
353
+
354
+ def initialize(data)
355
+ super(data, 'C')
356
+ end
357
+
358
+ end
359
+
360
+
361
+ end
@@ -0,0 +1,200 @@
1
+ require 'barby/barcode'
2
+
3
+ module Barby
4
+
5
+
6
+ class Code39 < Barcode1D
7
+
8
+ ENCODINGS = {
9
+ '0' => '101001101101', 'M' => '110110101001',
10
+ '1' => '110100101011', 'N' => '101011010011',
11
+ '2' => '101100101011', 'O' => '110101101001',
12
+ '3' => '110110010101', 'P' => '101101101001',
13
+ '4' => '101001101011', 'Q' => '101010110011',
14
+ '5' => '110100110101', 'R' => '110101011001',
15
+ '6' => '101100110101', 'S' => '101101011001',
16
+ '7' => '101001011011', 'T' => '101011011001',
17
+ '8' => '110100101101', 'U' => '110010101011',
18
+ '9' => '101100101101', 'V' => '100110101011',
19
+ 'A' => '110101001011', 'W' => '110011010101',
20
+ 'B' => '101101001011', 'X' => '100101101011',
21
+ 'C' => '110110100101', 'Y' => '110010110101',
22
+ 'D' => '101011001011', 'Z' => '100110110101',
23
+ 'E' => '110101100101', '-' => '100101011011',
24
+ 'F' => '101101100101', '.' => '110010101101',
25
+ 'G' => '101010011011', ' ' => '100110101101',
26
+ 'H' => '110101001101', '$' => '100100100101',
27
+ 'I' => '101101001101', '/' => '100100101001',
28
+ 'J' => '101011001101', '+' => '100101001001',
29
+ 'K' => '110101010011', '%' => '101001001001',
30
+ 'L' => '101101010011'#, '*' => '100101101101'
31
+ }
32
+
33
+ #In extended mode, each character is replaced with two characters from the "normal" encoding
34
+ EXTENDED_ENCODINGS = {
35
+ "\000" => '%U', " " => " ", "@" => "%V", "`" => "%W",
36
+ "\001" => '$A', "!" => "/A", "A" => "A", "a" => "+A",
37
+ "\002" => '$B', '"' => "/B", "B" => "B", "b" => "+B",
38
+ "\003" => '$C', "#" => "/C", "C" => "C", "c" => "+C",
39
+ "\004" => '$D', "$" => "/D", "D" => "D", "d" => "+D",
40
+ "\005" => '$E', "%" => "/E", "E" => "E", "e" => "+E",
41
+ "\006" => '$F', "&" => "/F", "F" => "F", "f" => "+F",
42
+ "\007" => '$G', "'" => "/G", "G" => "G", "g" => "+G",
43
+ "\010" => '$H', "(" => "/H", "H" => "H", "h" => "+H",
44
+ "\011" => '$I', ")" => "/I", "I" => "I", "i" => "+I",
45
+ "\012" => '$J', "*" => "/J", "J" => "J", "j" => "+J",
46
+ "\013" => '$K', "+" => "/K", "K" => "K", "k" => "+K",
47
+ "\014" => '$L', "," => "/L", "L" => "L", "l" => "+L",
48
+ "\015" => '$M', "-" => "-", "M" => "M", "m" => "+M",
49
+ "\016" => '$N', "." => ".", "N" => "N", "n" => "+N",
50
+ "\017" => '$O', "/" => "/O", "O" => "O", "o" => "+O",
51
+ "\020" => '$P', "0" => "0", "P" => "P", "p" => "+P",
52
+ "\021" => '$Q', "1" => "1", "Q" => "Q", "q" => "+Q",
53
+ "\022" => '$R', "2" => "2", "R" => "R", "r" => "+R",
54
+ "\023" => '$S', "3" => "3", "S" => "S", "s" => "+S",
55
+ "\024" => '$T', "4" => "4", "T" => "T", "t" => "+T",
56
+ "\025" => '$U', "5" => "5", "U" => "U", "u" => "+U",
57
+ "\026" => '$V', "6" => "6", "V" => "V", "v" => "+V",
58
+ "\027" => '$W', "7" => "7", "W" => "W", "w" => "+W",
59
+ "\030" => '$X', "8" => "8", "X" => "X", "x" => "+X",
60
+ "\031" => '$Y', "9" => "9", "Y" => "Y", "y" => "+Y",
61
+ "\032" => '$Z', ":" => "/Z", "Z" => "Z", "z" => "+Z",
62
+ "\033" => '%A', ";" => "%F", "[" => "%K", "{" => "%P",
63
+ "\034" => '%B', "<" => "%G", "\\" => "%L", "|" => "%Q",
64
+ "\035" => '%C', "=" => "%H", "]" => "%M", "}" => "%R",
65
+ "\036" => '%D', ">" => "%I", "^" => "%N", "~" => "%S",
66
+ "\037" => '%E', "?" => "%J", "_" => "%O", "\177" => "%T"
67
+ }
68
+
69
+ CHECKSUM_VALUES = {
70
+ '0' => 0, '1' => 1, '2' => 2, '3' => 3,
71
+ '4' => 4, '5' => 5, '6' => 6, '7' => 7,
72
+ '8' => 8, '9' => 9, 'A' => 10, 'B' => 11,
73
+ 'C' => 12, 'D' => 13, 'E' => 14, 'F' => 15,
74
+ 'G' => 16, 'H' => 17, 'I' => 18, 'J' => 19,
75
+ 'K' => 20, 'L' => 21, 'N' => 23, 'M' => 22,
76
+ 'O' => 24, 'P' => 25, 'Q' => 26, 'R' => 27,
77
+ 'S' => 28, 'T' => 29, 'U' => 30, 'V' => 31,
78
+ 'W' => 32, 'X' => 33, 'Y' => 34, 'Z' => 35,
79
+ '-' => 36, '.' => 37, ' ' => 38, '$' => 39,
80
+ '/' => 40, '+' => 41, '%' => 42
81
+ }
82
+
83
+ START_ENCODING = '100101101101' # *
84
+ STOP_ENCODING = '100101101101' # *
85
+
86
+ attr_accessor :data, :spacing, :extended, :include_checksum
87
+
88
+
89
+ def initialize(data, extended=false)
90
+ self.data = data
91
+ self.extended = extended
92
+ raise(ArgumentError, "data is not valid (extended=#{extended?})") unless valid?
93
+ yield self if block_given?
94
+ end
95
+
96
+
97
+ #Returns the characters that were passed in, no matter it they're part of
98
+ #the extended charset or if they're already encodable, "normal" characters
99
+ def raw_characters
100
+ data.split(//)
101
+ end
102
+
103
+ #Returns the encodable characters. If extended mode is enabled, each character will
104
+ #first be replaced by two characters from the encodable charset
105
+ def characters
106
+ chars = raw_characters
107
+ extended ? chars.map{|c| EXTENDED_ENCODINGS[c].split(//) }.flatten : chars
108
+ end
109
+
110
+ def characters_with_checksum
111
+ characters + [checksum_character]
112
+ end
113
+
114
+ def encoded_characters
115
+ characters.map{|c| ENCODINGS[c] }
116
+ end
117
+
118
+ def encoded_characters_with_checksum
119
+ encoded_characters + [checksum_encoding]
120
+ end
121
+
122
+
123
+ #The data part of the encoding (no start+stop characters)
124
+ def data_encoding
125
+ encoded_characters.join(spacing_encoding)
126
+ end
127
+
128
+ def data_encoding_with_checksum
129
+ encoded_characters_with_checksum.join(spacing_encoding)
130
+ end
131
+
132
+
133
+ def encoding
134
+ return encoding_with_checksum if include_checksum?
135
+ start_encoding+spacing_encoding+data_encoding+spacing_encoding+stop_encoding
136
+ end
137
+
138
+ def encoding_with_checksum
139
+ start_encoding+spacing_encoding+data_encoding_with_checksum+spacing_encoding+stop_encoding
140
+ end
141
+
142
+
143
+ #Checksum is optional
144
+ def checksum
145
+ characters.inject(0) do |sum,char|
146
+ sum + CHECKSUM_VALUES[char]
147
+ end % 43
148
+ end
149
+
150
+ def checksum_character
151
+ CHECKSUM_VALUES.invert[checksum]
152
+ end
153
+
154
+ def checksum_encoding
155
+ ENCODINGS[checksum_character]
156
+ end
157
+
158
+ #Set include_checksum to true to make +encoding+ include the checksum
159
+ def include_checksum?
160
+ include_checksum
161
+ end
162
+
163
+
164
+ #Spacing between the characters in xdims. Spacing will be inserted
165
+ #between each character in the encoding
166
+ def spacing
167
+ @spacing || 1
168
+ end
169
+
170
+ def spacing_encoding
171
+ '0' * spacing
172
+ end
173
+
174
+
175
+ def extended?
176
+ extended
177
+ end
178
+
179
+
180
+ def start_encoding
181
+ START_ENCODING
182
+ end
183
+
184
+ def stop_encoding
185
+ STOP_ENCODING
186
+ end
187
+
188
+ def valid?
189
+ if extended?
190
+ raw_characters.all?{|c| EXTENDED_ENCODINGS.include?(c) }
191
+ else
192
+ raw_characters.all?{|c| ENCODINGS.include?(c) }
193
+ end
194
+ end
195
+
196
+
197
+ end
198
+
199
+
200
+ end
@@ -0,0 +1,173 @@
1
+ require 'barby/barcode'
2
+
3
+ module Barby
4
+
5
+ #EAN-13, aka UPC-A, barcodes are the ones you can see at your local
6
+ #supermarket, in your house and, well, everywhere..
7
+ #
8
+ #To use this for a UPC barcode, just add a 0 to the front
9
+ class EAN13 < Barcode1D
10
+
11
+ LEFT_ENCODINGS_ODD = {
12
+ 0 => '0001101', 1 => '0011001', 2 => '0010011',
13
+ 3 => '0111101', 4 => '0100011', 5 => '0110001',
14
+ 6 => '0101111', 7 => '0111011', 8 => '0110111',
15
+ 9 => '0001011'
16
+ }
17
+
18
+ LEFT_ENCODINGS_EVEN = {
19
+ 0 => '0100111', 1 => '0110011', 2 => '0011011',
20
+ 3 => '0100001', 4 => '0011101', 5 => '0111001',
21
+ 6 => '0000101', 7 => '0010001', 8 => '0001001',
22
+ 9 => '0010111'
23
+ }
24
+
25
+ RIGHT_ENCODINGS = {
26
+ 0 => '1110010', 1 => '1100110', 2 => '1101100',
27
+ 3 => '1000010', 4 => '1011100', 5 => '1001110',
28
+ 6 => '1010000', 7 => '1000100', 8 => '1001000',
29
+ 9 => '1110100'
30
+ }
31
+
32
+ #Describes whether the left-hand encoding should use
33
+ #LEFT_ENCODINGS_ODD or LEFT_ENCODINGS_EVEN, based on the
34
+ #first digit in the number system (and the barcode as a whole)
35
+ LEFT_PARITY_MAPS = {
36
+ 0 => [:odd, :odd, :odd, :odd, :odd, :odd], #UPC-A
37
+ 1 => [:odd, :odd, :even, :odd, :even, :even],
38
+ 2 => [:odd, :odd, :even, :even, :odd, :even],
39
+ 3 => [:odd, :odd, :even, :even, :even, :odd],
40
+ 4 => [:odd, :even, :odd, :odd, :even, :even],
41
+ 5 => [:odd, :even, :even, :odd, :odd, :even],
42
+ 6 => [:odd, :even, :even, :even, :odd, :odd],
43
+ 7 => [:odd, :even, :odd, :even, :odd, :even],
44
+ 8 => [:odd, :even, :odd, :even, :even, :odd],
45
+ 9 => [:odd, :even, :even, :odd, :even, :odd]
46
+ }
47
+
48
+ #These are the lines that "stick down" in the graphical representation
49
+ START = '101'
50
+ CENTER = '01010'
51
+ STOP = '101'
52
+
53
+ #EAN-13 barcodes have 12 digits + check digit
54
+ FORMAT = /^\d{12}$/
55
+
56
+ attr_accessor :data
57
+
58
+
59
+ def initialize(data)
60
+ self.data = data
61
+ raise ArgumentError, 'data not valid' unless valid?
62
+ end
63
+
64
+
65
+ def characters
66
+ data.split(//)
67
+ end
68
+
69
+ def numbers
70
+ characters.map{|s| s.to_i }
71
+ end
72
+
73
+ def odd_and_even_numbers
74
+ alternater = false
75
+ numbers.reverse.partition{ alternater = !alternater }
76
+ end
77
+
78
+ #Numbers that are encoded to the left of the center
79
+ #The first digit is not included
80
+ def left_numbers
81
+ numbers[1,6]
82
+ end
83
+
84
+ #Numbers that are encoded to the right of the center
85
+ #The checksum is included here
86
+ def right_numbers
87
+ numbers_with_checksum[7,6]
88
+ end
89
+
90
+ def numbers_with_checksum
91
+ numbers + [checksum]
92
+ end
93
+
94
+
95
+ def data_with_checksum
96
+ data + checksum.to_s
97
+ end
98
+
99
+
100
+ def left_encodings
101
+ left_parity_map.zip(left_numbers).map do |parity,number|
102
+ parity == :odd ? LEFT_ENCODINGS_ODD[number] : LEFT_ENCODINGS_EVEN[number]
103
+ end
104
+ end
105
+
106
+ def right_encodings
107
+ right_numbers.map{|n| RIGHT_ENCODINGS[n] }
108
+ end
109
+
110
+ def left_encoding
111
+ left_encodings.join
112
+ end
113
+
114
+ def right_encoding
115
+ right_encodings.join
116
+ end
117
+
118
+ def encoding
119
+ start_encoding+left_encoding+center_encoding+right_encoding+stop_encoding
120
+ end
121
+
122
+
123
+ #The parities to use for encoding left-hand numbers
124
+ def left_parity_map
125
+ LEFT_PARITY_MAPS[numbers.first]
126
+ end
127
+
128
+
129
+ def weighted_sum
130
+ odds, evens = odd_and_even_numbers
131
+ odds.map!{|n| n * 3 }
132
+ sum = (odds+evens).inject(0){|s,n| s+n }
133
+ end
134
+
135
+ #Mod10
136
+ def checksum
137
+ mod = weighted_sum % 10
138
+ mod.zero? ? 0 : 10-mod
139
+ end
140
+
141
+ def checksum_encoding
142
+ RIGHT_ENCODINGS[checksum]
143
+ end
144
+
145
+
146
+ def valid?
147
+ data =~ FORMAT
148
+ end
149
+
150
+
151
+ #Is this a UPC-A barcode?
152
+ #UPC barcodes are EAN codes that start with 0
153
+ def upc?
154
+ numbers.first.zero?
155
+ end
156
+
157
+
158
+ def start_encoding
159
+ START
160
+ end
161
+
162
+ def center_encoding
163
+ CENTER
164
+ end
165
+
166
+ def stop_encoding
167
+ STOP
168
+ end
169
+
170
+
171
+ end
172
+
173
+ end
@@ -0,0 +1,32 @@
1
+ require 'barby/barcode/ean_13'
2
+
3
+ module Barby
4
+
5
+ #EAN-8 is a sub-set of EAN-13, with only 7 (8) digits
6
+ class EAN8 < EAN13
7
+
8
+ FORMAT = /^\d{7}$/
9
+
10
+
11
+ def left_numbers
12
+ numbers[0,4]
13
+ end
14
+
15
+ def right_numbers
16
+ numbers_with_checksum[4,4]
17
+ end
18
+
19
+
20
+ #Left-hand digits are all encoded using odd parity
21
+ def left_parity_map
22
+ [:odd, :odd, :odd, :odd]
23
+ end
24
+
25
+
26
+ def valid?
27
+ data =~ FORMAT
28
+ end
29
+
30
+ end
31
+
32
+ end
@@ -0,0 +1,37 @@
1
+ require 'barby/barcode/code_128'
2
+
3
+ module Barby
4
+
5
+
6
+ #AKA EAN-128, UCC-128
7
+ class GS1128 < Code128
8
+
9
+ attr_accessor :application_identifier
10
+
11
+ def initialize(data, type, ai)
12
+ self.application_identifier = ai
13
+ super(data, type)
14
+ end
15
+
16
+
17
+ def data
18
+ FNC1+application_identifier+super
19
+ end
20
+
21
+ def partial_data
22
+ @data
23
+ end
24
+
25
+ def application_identifier_number
26
+ values[application_identifier]
27
+ end
28
+
29
+ def application_identifier_encoding
30
+ encodings[application_identifier_number]
31
+ end
32
+
33
+
34
+ end
35
+
36
+
37
+ end
@@ -0,0 +1,73 @@
1
+ require 'barby/barcode'
2
+
3
+ module Barby
4
+
5
+
6
+ #An Outputter creates something from a barcode. That something can be
7
+ #anything, but is most likely a graphical representation of the barcode.
8
+ #Outputters can register methods on barcodes that will be associated with
9
+ #them.
10
+ #
11
+ #The basic structure of an outputter class:
12
+ #
13
+ # class FooOutputter < Barby::Outputter
14
+ # register :to_foo
15
+ # def to_too
16
+ # do_something_with(barcode.encoding)
17
+ # end
18
+ # end
19
+ #
20
+ #Barcode#to_foo will now be available to all barcodes
21
+ class Outputter
22
+
23
+ attr_accessor :barcode
24
+
25
+
26
+ #An outputter instance will have access to a Barcode
27
+ def initialize(barcode)
28
+ self.barcode = barcode
29
+ end
30
+
31
+
32
+ #Register one or more handler methods with this outputter
33
+ #Barcodes will then be able to use these methods to get the output
34
+ #from the outputter. For example, if you have an ImageOutputter,
35
+ #you could do:
36
+ #
37
+ #register :to_png, :to_gif
38
+ #
39
+ #You could then do aBarcode.to_png and get the result of that method.
40
+ #The class which registers the method will receive the barcode as the only
41
+ #argument, and the default implementation of initialize puts that into
42
+ #the +barcode+ accessor.
43
+ #
44
+ #You can also have different method names on the barcode and the outputter
45
+ #by providing a hash:
46
+ #
47
+ #register :to_png => :create_png, :to_gif => :create_gif
48
+ def self.register(*method_names)
49
+ if method_names.first.is_a? Hash
50
+ method_names.first.each do |name, method_name|
51
+ Barcode.register_outputter(name, self, method_name)
52
+ end
53
+ else
54
+ method_names.each do |name|
55
+ Barcode.register_outputter(name, self, name)
56
+ end
57
+ end
58
+ end
59
+
60
+
61
+ private
62
+
63
+ #Converts the barcode's encoding (a string containing 1s and 0s)
64
+ #to true and false values (1 == true == "black bar")
65
+ def booleans#:doc:
66
+ barcode.encoding.split(//).map{|c| c == '1' }
67
+ end
68
+
69
+
70
+ end
71
+
72
+
73
+ end
@@ -0,0 +1,22 @@
1
+ require 'barby/outputter'
2
+
3
+ module Barby
4
+
5
+ #Outputs an ASCII representation of the barcode. This is mostly useful for printing
6
+ #the barcode directly to the terminal for testing.
7
+ class ASCIIOutputter < Outputter
8
+
9
+ register :to_ascii
10
+
11
+
12
+ def to_ascii(opts={})
13
+ opts = {:height => 10, :xdim => 1, :bar => '#', :space => ' '}.merge(opts)
14
+ Array.new(
15
+ opts[:height],
16
+ booleans.map{|b| (b ? opts[:bar] : opts[:space]) * opts[:xdim] }.join
17
+ ).join("\n")
18
+ end
19
+
20
+ end
21
+
22
+ end
@@ -0,0 +1,74 @@
1
+ require 'barby/outputter'
2
+
3
+ module Barby
4
+
5
+ class PDFWriterOutputter < Outputter
6
+
7
+ register :annotate_pdf
8
+
9
+ attr_accessor :x, :y, :height, :xdim
10
+
11
+
12
+ def annotate_pdf(pdf, options={})
13
+ previous_options = options.map{|k,v| [k, send(k)] }
14
+ options.each{|k,v| send("#{k}=", v) if respond_to?("#{k}=") }
15
+
16
+ xpos, ypos = x, y
17
+
18
+ widths.each do |array|
19
+ if array.first
20
+ pdf.move_to(xpos, ypos).
21
+ line_to(xpos, ypos+height).
22
+ line_to(xpos+(xdim*array.size), ypos+height).
23
+ line_to(xpos+(xdim*array.size), ypos).
24
+ line_to(xpos, ypos).
25
+ fill
26
+ end
27
+ xpos += (xdim*array.size)
28
+ end
29
+
30
+ previous_options.each{|k,v| send("#{k}=", v) }
31
+
32
+ pdf
33
+ end
34
+
35
+
36
+ def x
37
+ @x || 10
38
+ end
39
+
40
+ def y
41
+ @y || 10
42
+ end
43
+
44
+ def height
45
+ @height || 50
46
+ end
47
+
48
+ def xdim
49
+ @xdim || 1
50
+ end
51
+
52
+ def widths
53
+ widths = []
54
+ count = nil
55
+
56
+ booleans.inject nil do |last,current|
57
+ if current != last
58
+ widths << count if count
59
+ count = [current]
60
+ else
61
+ count << current
62
+ end
63
+ current
64
+ end
65
+
66
+ widths << count
67
+
68
+ widths
69
+ end
70
+
71
+
72
+ end
73
+
74
+ end
@@ -0,0 +1,87 @@
1
+ require 'barby/outputter'
2
+ require 'RMagick'
3
+
4
+ module Barby
5
+
6
+
7
+ #Renders images from barcodes using RMagick
8
+ class RmagickOutputter < Outputter
9
+
10
+ register :to_png, :to_gif, :to_jpg, :to_image
11
+
12
+ attr_accessor :height, :xdim, :margin
13
+
14
+
15
+ #Returns a string containing a PNG image
16
+ def to_png(*a)
17
+ to_image(*a).to_blob{|i| i.format ='png' }
18
+ end
19
+
20
+ #Returns a string containint a GIF image
21
+ def to_gif(*a)
22
+ to_image(*a).to_blob{|i| i.format ='gif' }
23
+ end
24
+
25
+ #Returns a string containing a JPEG image
26
+ def to_jpg(*a)
27
+ to_image(*a).to_blob{|i| i.format = 'jpg' }
28
+ end
29
+
30
+ #Returns an instance of Magick::Image
31
+ def to_image(opts={})
32
+ opts.each{|k,v| send("#{k}=", v) if respond_to?("#{k}=") }
33
+ canvas = Magick::Image.new(full_width, full_height)
34
+ bars = Magick::Draw.new
35
+
36
+ x = margin
37
+ y = margin
38
+ booleans.each do |bar|
39
+ if bar
40
+ bars.rectangle(x, y, x+(xdim-1), y+height)
41
+ end
42
+ x += xdim
43
+ end
44
+
45
+ bars.draw(canvas)
46
+
47
+ canvas
48
+ end
49
+
50
+
51
+ #The height of the barcode in px
52
+ def height
53
+ @height || 100
54
+ end
55
+
56
+ #X dimension. 1X == 1px
57
+ def xdim
58
+ @xdim || 1
59
+ end
60
+
61
+ #The margin of each edge surrounding the barcode in pixels
62
+ def margin
63
+ @margin || 10
64
+ end
65
+
66
+ #The width of the barcode in px
67
+ def width
68
+ barcode.encoding.length * xdim
69
+ end
70
+
71
+ #The full width of the image. This is the width of the
72
+ #barcode + the left and right margin
73
+ def full_width
74
+ width + (margin * 2)
75
+ end
76
+
77
+ #The height of the image. This is the height of the
78
+ #barcode + the top and bottom margin
79
+ def full_height
80
+ height + (margin * 2)
81
+ end
82
+
83
+
84
+ end
85
+
86
+
87
+ end
@@ -0,0 +1,9 @@
1
+ module Barby #:nodoc:
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ TINY = 0
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: barby
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Tore Darell
8
+ autorequire: barby
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-03-17 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: toredarell@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ files:
25
+ - lib/barby.rb
26
+ - lib/barby
27
+ - lib/barby/barcode.rb
28
+ - lib/barby/barcode
29
+ - lib/barby/barcode/bookland.rb
30
+ - lib/barby/barcode/code_128.rb
31
+ - lib/barby/barcode/code_39.rb
32
+ - lib/barby/barcode/ean_13.rb
33
+ - lib/barby/barcode/ean_8.rb
34
+ - lib/barby/barcode/gs1_128.rb
35
+ - lib/barby/outputter.rb
36
+ - lib/barby/outputter
37
+ - lib/barby/outputter/ascii_outputter.rb
38
+ - lib/barby/outputter/pdfwriter_outputter.rb
39
+ - lib/barby/outputter/rmagick_outputter.rb
40
+ - lib/barby/version.rb
41
+ - README
42
+ has_rdoc: true
43
+ homepage: http://tore.darell.no/
44
+ post_install_message:
45
+ rdoc_options: []
46
+
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ requirements: []
62
+
63
+ rubyforge_project:
64
+ rubygems_version: 1.0.1
65
+ signing_key:
66
+ specification_version: 2
67
+ summary: A pure-Ruby barcode generator
68
+ test_files: []
69
+