zebra-zpl 1.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 02d6f5e561ffabed62717502d3f762fa518bfd00
4
+ data.tar.gz: 3bcba1f5caedeebf16bea8e9018021f116644378
5
+ SHA512:
6
+ metadata.gz: 3e3fd2f85335014ff4afe6350aef68752fd7dd318a4c02e1823a55620361e2e571626708b227e096274cb38540cced96c326b13add7b51e6fca8819dd7bdf7f4
7
+ data.tar.gz: e5dad045be5b3eb38bb74749f3c3eabb7196f1da24b1c5e3f5a4f091f4a0e1c5694c8a06832f5ad58d8faf9a6899f39ef987954d79c08597b01568a90ebf3e8a
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ tags
19
+ bin
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in zebra-zpl.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,11 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec', cmd: "bundle exec rspec" do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+
9
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
10
+ end
11
+
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 bulpettb
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Cássio Marques
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,180 @@
1
+ #### This is a gem based on a terrific older gem by Cassio Marques. Although the new printers are mostly compatible with old Eltron (Epl) code, my needs require many of the new Zebra (ZPL) functions.
2
+
3
+ # Zebra::Zpl
4
+
5
+ ### ToDo: Update documentation with instructions for new features such as font sizing, margins, and text alignment
6
+
7
+ Zebra::Zpl offers a Ruby DSL to design and print labels using the ZPL programming language.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'zebra-zpl'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install zebra-zpl
22
+
23
+ ## Usage
24
+
25
+ ### Building labels
26
+
27
+ You create new labels with an instance of the `Zebra::Zpl::Label` class. It accepts the following options:
28
+
29
+ * `copies`: The number of copies to print. This option defaults to 1.
30
+ * `width`: The label's width, in dots.
31
+ * `length`: The label's length, is dots.
32
+ * `gap`: The gap between labels, in dots.
33
+ * `print_speed`: The print speed to be used. You can use values between 0 and 6. This option is required.
34
+ * `print_density`: The print density to be used. You can use values between 0 and 15. This option is required.
35
+
36
+ With a label, you can start adding elements to it:
37
+
38
+ label = Zebra::Zpl::Label.new :print_density => 8, :print_speed => 3
39
+ text = Zebra::Zpl::Text.new :data => "Hello, printer!", :position => [100, 100], :font_size => Zebra::Zpl::FontSize::SIZE_2
40
+ label << text
41
+
42
+ You can add as many elements as you want.
43
+
44
+ ### Printing the labels
45
+
46
+ You need to have your printer visible to CUPS. Once your printer is configured and you know its name on CUPS, you can send the labels to the printer using a `Zebra::PrintJob` instance.
47
+
48
+ label = Zebra::Zpl::Label.new(
49
+ :width => 200,
50
+ :length => 200,
51
+ :print_speed => 3,
52
+ :print_density => 6
53
+ )
54
+
55
+
56
+ barcode = Zebra::Zpl::Barcode.new(
57
+ :data => "12345678",
58
+ :position => [50, 50],
59
+ :height => 50,
60
+ :print_human_readable_code => true,
61
+ :narrow_bar_width => 4,
62
+ :wide_bar_width => 8,
63
+ :type => Zebra::Zpl::BarcodeType::CODE_128_AUTO
64
+ )
65
+
66
+ label << barcode
67
+
68
+ print_job = Zebra::PrintJob.new "your-printer-name-on-cups"
69
+
70
+ print_job.print label
71
+
72
+ This will persist the label contents to a tempfile (using Ruby's tempfile core library) and copy the file to the printer using either `lpr -P <your-printer-name-on-cups> -o raw <path-to-the-temp-file>` (if you're on Mac OSX) or `lp -d <your-printer-name-on-cups> -o raw <path-to-the-tempfile>` (if you're on Linux). All the tempfile creation/path resolution, as well as which command has to be used, are handled by the `PrintJob` class.
73
+
74
+ ### Printing QR codes
75
+
76
+ label = Zebra::Zpl::Label.new(
77
+ :width=>350,
78
+ :length=>250,
79
+ :print_speed=>3,
80
+ :print_density=>6
81
+ )
82
+
83
+ qrcode = Zebra::Zpl::Qrcode.new(
84
+ :data=>"www.github.com",
85
+ :position=>[50,10],
86
+ :scale_factor=>3,
87
+ :correction_level=>"H"
88
+ )
89
+
90
+ label << qrcode
91
+
92
+ print_job = Zebra::PrintJob.new "your-qr-printer-name-on-cups"
93
+
94
+ print_job.print label
95
+
96
+ ### Available elements
97
+
98
+ #### Text
99
+
100
+ You create text elements to print using instances of the `Zebra::Zpl::Text` class. It accepts the following options:
101
+
102
+ * `position`: An array with the coordinates to place the text, in dots.
103
+ * `rotation`: The rotation for the text. More about the possible values below.
104
+ * `data`: The text to be printed.
105
+ * `v_multiplier`: The vertical multiplier to use.
106
+ * `h_multiplier`: The horizontal multipler to use.
107
+ * `print_mode`: The print mode. Can be normal ("N") or reverse ("R").
108
+ * `font_size`: The font size to use. You can use values between 1 and 5.
109
+
110
+ For the print modes, you can also use the constants:
111
+
112
+ * `Zebra::Zpl::PrintMode::NORMAL`
113
+ * `Zebra::Zpl::PrintMode::REVERSE`
114
+
115
+
116
+ #### Barcodes
117
+
118
+ You create barcode elements to print using instances of the `Zebra::Zpl::Barcode` class. It accepts the following options:
119
+
120
+ * `position`: An array with the coordinates to place the text, in dots.
121
+ * `height`: The barcode's height, in dots.
122
+ * `rotation`: The rotation for the text. More about the possible values below.
123
+ * `data`: The text to be printed.
124
+ * `type`: The type os barcode to use. More on the available types below.
125
+ * `narrow_bar_width`: The barcode's narrow bar width, in dots.
126
+ * `wide_bar_width`: The barcode's wide bar width, in dots.
127
+ * `print_human_readable_code`: Can be `true` or `false`, indicates if the human readable contents should be printed below the barcode.
128
+
129
+ The available barcode types are:
130
+
131
+ * `Zebra::Zpl::BarcodeType::CODE_39`
132
+ * `Zebra::Zpl::BarcodeType::CODE_93`
133
+ * `Zebra::Zpl::BarcodeType::CODE_128_AUTO`
134
+ * `Zebra::Zpl::BarcodeType::CODABAR`
135
+ * `Zebra::Zpl::BarcodeType::CODE_AZTEC`
136
+ * `Zebra::Zpl::BarcodeType::CODE_AZTEC_PARAMS`
137
+ * `Zebra::Zpl::BarcodeType::CODE_UPS_MAXICODE`
138
+ * `Zebra::Zpl::BarcodeType::CODE_QR`
139
+
140
+ #### QR Codes
141
+
142
+ You can create QR Codes elements to print using instances of the `Zebra::Zpl::Qrcode` class. It accepts the following options:
143
+
144
+ * `position`: An array with the coordinates to place the QR code, in dots.
145
+ * `scale factor`: Crucial variable of the QR codes's size. Accepted values: 1-99.
146
+ * `error correction level`: Algorithm enables reading damaged QR codes. There are four error correction levels: L - 7% of codewords can be restored, M - 15% can be restored, Q - 25% can be restored, H - 30% can be restored.
147
+
148
+ #### Boxes
149
+
150
+ You can draw boxes in your labels:
151
+
152
+ box = Zebra::Zpl::Box.new :position => [20, 20], :end_position => [100, 100], :line_thickness => 39
153
+
154
+ #### Elements Rotation
155
+
156
+ All printable elements can be rotated on the label, using the `:Rotation` option. The accepted rotation values are:
157
+
158
+ * `Zebra::Zpl::Rotation::NO_ROTATION`: will not rotate the element.
159
+ * `Zebra::Zpl::Rotation::DEGREES_90`: will rotate the element 90 degrees.
160
+ * `Zebra::Zpl::Rotation::DEGREES_180`: will rotate the element 180 degrees.
161
+ * `Zebra::Zpl::Rotation::DEGREES_270`: will rotate the element 270 degrees.
162
+
163
+ #### Elements Justification
164
+
165
+ There are four ZPL-supported `:Justification` parameters. "LEFT" (left-justified) is the default.
166
+
167
+ * `Zebra::Zpl::Justification::LEFT` ~ left-justified
168
+ * `Zebra::Zpl::Justification::RIGHT` ~ right-justified
169
+ * `Zebra::Zpl::Justification::CENTER` ~ centered
170
+ * `Zebra::Zpl::Justification::JUSTIFIED` ~ full-width-justifed _(YMMV)_
171
+
172
+
173
+
174
+ ## Contributing
175
+
176
+ 1. Fork it
177
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
178
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
179
+ 4. Push to the branch (`git push origin my-new-feature`)
180
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,35 @@
1
+ module Zebra
2
+ class PrintJob
3
+ # class UnknownPrinter < StandardError
4
+ # def initialize(printer)
5
+ # super("Could not find a printer named #{printer}")
6
+ # end
7
+ # end
8
+
9
+ attr_reader :printer
10
+
11
+ def initialize(printer)
12
+ #check_existent_printers printer
13
+
14
+ @printer = printer
15
+ end
16
+
17
+ def print(label, ip)
18
+ @remote_ip = ip
19
+ tempfile = label.persist
20
+ send_to_printer tempfile.path
21
+ end
22
+
23
+ private
24
+
25
+ # def check_existent_printers(printer)
26
+ # existent_printers = Cups.show_destinations
27
+ # raise UnknownPrinter.new(printer) unless existent_printers.include?(printer)
28
+ # end
29
+
30
+ def send_to_printer(path)
31
+ puts "* * * * * * * * * * * * Sending file to printer #{@printer} at #{@remote_ip} * * * * * * * * * * "
32
+ `lp -h #{@remote_ip} -d #{@printer} -o raw #{path}`
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,55 @@
1
+ require "zebra/zpl/printable"
2
+
3
+ module Zebra
4
+ module Zpl
5
+ class Barcode
6
+ include Printable
7
+
8
+ class InvalidNarrowBarWidthError < StandardError; end
9
+ class InvalidWideBarWidthError < StandardError; end
10
+
11
+ attr_accessor :height
12
+ attr_reader :type, :narrow_bar_width, :wide_bar_width, :width
13
+ attr_writer :print_human_readable_code
14
+
15
+ def width=(width)
16
+ @width = width || 0
17
+ end
18
+
19
+ def type=(type)
20
+ BarcodeType.validate_barcode_type(type)
21
+ @type = type
22
+ end
23
+
24
+ def narrow_bar_width=(width)
25
+ raise InvalidNarrowBarWidthError unless (1..10).include?(width.to_i)
26
+ @narrow_bar_width = width
27
+ end
28
+
29
+ def wide_bar_width=(width)
30
+ raise InvalidWideBarWidthError unless (2..30).include?(width.to_i)
31
+ @wide_bar_width = width
32
+ end
33
+
34
+ def print_human_readable_code
35
+ @print_human_readable_code || false
36
+ end
37
+
38
+ def to_zpl
39
+ check_attributes
40
+ human_readable = print_human_readable_code ? "Y" : "N"
41
+ "^FW#{rotation}^FO#{x},#{y}^BY#{narrow_bar_width}^B#{type}#{rotation},#{height},#{human_readable}^FD#{data}^FS"
42
+ end
43
+
44
+ private
45
+
46
+ def check_attributes
47
+ super
48
+ raise MissingAttributeError.new("the barcode type to be used is not given") unless @type
49
+ raise MissingAttributeError.new("the height to be used is not given") unless @height
50
+ raise MissingAttributeError.new("the narrow bar width to be used is not given") unless @narrow_bar_width
51
+ raise MissingAttributeError.new("the wide bar width to be used is not given") unless @wide_bar_width
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,34 @@
1
+ module Zebra
2
+ module Zpl
3
+ module BarcodeType
4
+ class InvalidBarcodeTypeError < StandardError; end
5
+
6
+ CODE_39 = "3"
7
+ CODE_93 = "A"
8
+ CODE_128_AUTO = "C"
9
+ CODABAR = "K"
10
+ CODE_AZTEC = "0"
11
+ CODE_AZTEC_PARAMS = "O"
12
+ CODE_UPS_MAXICODE = "D"
13
+ CODE_QR = "Q"
14
+
15
+ # Legacy (EPL) bar code suffixes
16
+ # CODE_39 = "3"
17
+ # CODE_39_CHECK_DIGIT = "3C"
18
+ # CODE_93 = "9"
19
+ # CODE_128_AUTO = "1"
20
+ # CODE_128_A = "1A"
21
+ # CODE_128_B = "1B"
22
+ # CODE_128_C = "1C"
23
+ # CODABAR = "K"
24
+
25
+ def self.valid_barcode_type?(type)
26
+ %w(3 A C K 0 O D Q).include? type
27
+ end
28
+
29
+ def self.validate_barcode_type(type)
30
+ raise InvalidBarcodeTypeError unless valid_barcode_type?(type)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,50 @@
1
+ require "zebra/zpl/printable"
2
+
3
+ module Zebra
4
+ module Zpl
5
+ class Box
6
+ include Printable
7
+
8
+ class InvalidLineThickness < StandardError; end
9
+
10
+ attr_reader :line_thickness, :box_width, :box_height, :width
11
+
12
+ def line_thickness=(thickness)
13
+ raise InvalidLineThickness unless thickness.nil? || thickness.to_i.to_s == thickness.to_s
14
+ @line_thickness = thickness
15
+ end
16
+
17
+ def box_width=(width)
18
+ @box_width = width
19
+ end
20
+
21
+ ### The method below refers to the "label width"
22
+ def width=(width)
23
+ @width = width || 0
24
+ end
25
+
26
+ def box_height=(height)
27
+ @box_height = height
28
+ end
29
+
30
+ def to_zpl
31
+ check_attributes
32
+ # "^FO#{x},#{y}^GB#{box_width},#{box_height},#{line_thickness}^FS"
33
+ "^FO#{x},#{y}^GB#{box_width},#{box_height},#{line_thickness}^FS"
34
+ end
35
+
36
+ private
37
+
38
+ def has_data?
39
+ false
40
+ end
41
+
42
+ def check_attributes
43
+ super
44
+ raise MissingAttributeError.new("the line thickness is not given") unless line_thickness
45
+ raise MissingAttributeError.new("the box_width is not given") unless box_width
46
+ raise MissingAttributeError.new("the box_height is not given") unless box_height
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+ module Zebra
3
+ module Zpl
4
+ class CharacterSet
5
+ class InvalidNumberOfDataBits < StandardError; end
6
+ class CountryCodeNotApplicableForNumberOfDataBits < StandardError; end
7
+ class MissingAttributeError < StandardError
8
+ def initialize(attr)
9
+ super("Can't set character set if the #{attr} is not given")
10
+ end
11
+ end
12
+
13
+ attr_reader :number_of_data_bits, :language, :country_code
14
+
15
+ def initialize(options = {})
16
+ options.each_pair { |attribute, value| self.__send__ "#{attribute}=", value }
17
+ end
18
+
19
+ def number_of_data_bits=(nodb)
20
+ raise InvalidNumberOfDataBits unless [7, 8, nil].include?(nodb)
21
+ @number_of_data_bits = nodb
22
+ end
23
+
24
+ def language=(l)
25
+ Language.validate_language(l) unless l.nil?
26
+ @language = l
27
+ end
28
+
29
+ def country_code=(code)
30
+ CountryCode.validate_country_code(code) unless code.nil?
31
+ @country_code = code
32
+ end
33
+
34
+ def to_zpl
35
+ raise MissingAttributeError.new("language") if language.nil?
36
+ raise MissingAttributeError.new("number of data bits") if number_of_data_bits.nil?
37
+ raise MissingAttributeError.new("country code") if number_of_data_bits == 8 && country_code.nil?
38
+ raise CountryCodeNotApplicableForNumberOfDataBits if number_of_data_bits == 7 && !country_code.nil?
39
+ Language.validate_language_for_number_of_data_bits language, number_of_data_bits
40
+
41
+ ["I#{number_of_data_bits}", language, country_code].compact.join(",")
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+ module Zebra
3
+ module Zpl
4
+ class CountryCode
5
+ class InvalidCountryCodeError < StandardError; end
6
+
7
+ BELGIUM = "032"
8
+ CANADA = "002"
9
+ DENMARK = "045"
10
+ FINLAND = "358"
11
+ FRANCE = "033"
12
+ GERMANY = "049"
13
+ NETHERLANDS = "031"
14
+ ITALY = "039"
15
+ LATIN_AMERICA = "003"
16
+ NORWAY = "047"
17
+ PORTUGAL = "351"
18
+ SOUTH_AFRICA = "027"
19
+ SPAIN = "034"
20
+ SWEDEN = "046"
21
+ SWITZERLAND = "041"
22
+ UK = "044"
23
+ USA = "001"
24
+
25
+ def self.valid_country_code?(code)
26
+ [BELGIUM, CANADA, DENMARK, FINLAND, FRANCE, GERMANY, NETHERLANDS,
27
+ ITALY, LATIN_AMERICA, NORWAY, PORTUGAL, SOUTH_AFRICA, SPAIN, SWEDEN, SWITZERLAND,
28
+ UK, USA].include?(code)
29
+ end
30
+
31
+ def self.validate_country_code(code)
32
+ raise InvalidCountryCodeError unless valid_country_code?(code)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,47 @@
1
+ module Zebra
2
+ module Zpl
3
+ module FontSize
4
+ class InvalidFontSizeError < StandardError; end
5
+
6
+ SIZE_0 = 12 # tiny
7
+ SIZE_1 = 17 # 6pt
8
+ SIZE_2 = 22 # 8pt
9
+ SIZE_3 = 28 # 10pt
10
+ SIZE_4 = 33 # 12pt
11
+ SIZE_5 = 44 # 16pt
12
+ SIZE_6 = 67 # 24pt
13
+ SIZE_7 = 100 # 32pt
14
+ SIZE_8 = 111 # 40pt
15
+ SIZE_9 = 133 # 48pt
16
+
17
+ def self.valid_font_size?(font_size)
18
+ [12, 17, 22, 28, 33, 44, 67, 100, 111, 133].include?(font_size.to_i)
19
+ end
20
+
21
+ def self.validate_font_size(font_size)
22
+ raise InvalidFontSizeError unless valid_font_size?(font_size)
23
+ end
24
+ end
25
+
26
+ module FontType
27
+ class InvalidFontTypeError < StandardError; end
28
+
29
+ TYPE_0 = "0" # 6pt
30
+ TYPE_CD = "CD" # 6pt
31
+ TYPE_A = "A" # 6pt
32
+ TYPE_B = "B" # 6pt
33
+ TYPE_E = "E" # 6pt
34
+ TYPE_F = "F" # 6pt
35
+ TYPE_G = "G" # 6pt
36
+ TYPE_H = "H" # 6pt
37
+
38
+ def self.valid_font_type?(font_type)
39
+ ["0", "CD", "A", "B", "E", "F", "G", "H"].include?(font_type)
40
+ end
41
+
42
+ def self.validate_font_type(font_type)
43
+ raise InvalidFontTypeError unless valid_font_type?(font_type)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,21 @@
1
+ module Zebra
2
+ module Zpl
3
+ module Justification
4
+ class InvalidJustificationError < StandardError; end
5
+
6
+ # ZPL-supported values ("L" is default)
7
+ LEFT = 'L'
8
+ RIGHT = 'R'
9
+ CENTER = 'C'
10
+ JUSTIFIED = 'J'
11
+
12
+ def self.valid_justification?(justification)
13
+ [LEFT, RIGHT, CENTER, JUSTIFIED].include? justification
14
+ end
15
+
16
+ def self.validate_justification(justification)
17
+ raise InvalidJustificationError unless valid_justification?(justification)
18
+ end
19
+ end
20
+ end
21
+ end