zebra-zpl 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,97 @@
1
+ # encoding: utf-8
2
+
3
+ module Zebra
4
+ module Zpl
5
+ class Label
6
+ class InvalidPrintSpeedError < StandardError; end
7
+ class InvalidPrintDensityError < StandardError; end
8
+ class PrintSpeedNotInformedError < StandardError; end
9
+
10
+ attr_writer :copies
11
+ attr_reader :elements, :tempfile
12
+ attr_accessor :width, :length, :gap, :print_speed, :print_density
13
+
14
+ def initialize(options = {})
15
+ options.each_pair { |key, value| self.__send__("#{key}=", value) if self.respond_to?("#{key}=") }
16
+ @elements = []
17
+ end
18
+
19
+ def length_and_gap=(length_and_gap)
20
+ self.length = length_and_gap[0]
21
+ self.gap = length_and_gap[1]
22
+ end
23
+
24
+ def print_speed=(s)
25
+ raise InvalidPrintSpeedError unless (0..6).include?(s)
26
+ @print_speed = s
27
+ end
28
+
29
+ def print_density=(d)
30
+ raise InvalidPrintDensityError unless (0..6).include?(d)
31
+ @print_density = d
32
+ end
33
+
34
+ def copies
35
+ @copies || 1
36
+ end
37
+
38
+ def <<(element)
39
+ element.width = self.width
40
+ elements << element
41
+ end
42
+
43
+ def dump_contents(io = STDOUT)
44
+ check_required_configurations
45
+ # Start format
46
+ io << "^XA"
47
+ # ^LL<label height in dots>,<space between labels in dots>
48
+ # io << "^LL#{length},#{gap}\n" if length && gap
49
+ io << "^LL#{length}" if length
50
+ # ^LH<label home - x,y coordinates of top left label>
51
+ io << "^LH0,0"
52
+ # ^LS<shift the label to the left(or right)>
53
+ io << "^LS10"
54
+ # ^PW<label width in dots>
55
+ io << "^PW#{width}" if width
56
+ # Print Rate(speed) (^PR command)
57
+ io << "^PR#{print_speed}"
58
+ # Density (D command) "Carried over from EPL, does this exist in ZPL ????"
59
+ # io << "D#{print_density}\n" if print_density
60
+
61
+ # TEST ZPL (comment everything else out)...
62
+ # io << "^XA^WD*:*.FNT*^XZ"
63
+ # TEST ZPL SEGMENT
64
+ # io << "^WD*:*.FNT*"
65
+ # TEST AND GET CONFIGS
66
+ # io << "^HH"
67
+
68
+ elements.each do |element|
69
+ io << element.to_zpl
70
+ end
71
+ # Specify how many copies to print
72
+ io << "^PQ#{copies}"
73
+ # End format
74
+ io << "^XZ"
75
+ end
76
+
77
+ def persist
78
+ # debugger
79
+ tempfile = Tempfile.new "zebra_label"
80
+ dump_contents tempfile
81
+ tempfile.close
82
+ @tempfile = tempfile
83
+ tempfile
84
+ end
85
+
86
+ def persisted?
87
+ !!self.tempfile
88
+ end
89
+
90
+ private
91
+
92
+ def check_required_configurations
93
+ raise PrintSpeedNotInformedError unless print_speed
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,76 @@
1
+ # encoding: utf-8
2
+ module Zebra
3
+ module Zpl
4
+ class Language
5
+ class InvalidLanguageError < StandardError; end
6
+ class InvalidLanguageForNumberOfDataBitsError < StandardError; end
7
+
8
+ # 8 bits languages
9
+ ENGLISH_US = "0"
10
+ LATIN_1 = "1"
11
+ LATIN_2 = "2"
12
+ PORTUGUESE = "3"
13
+ FRENCH_CANADIAN = "4"
14
+ NORDIC = "5"
15
+ TURKISH = "6"
16
+ ICELANDIC = "7"
17
+ HEBREW = "8"
18
+ CYRILLIC = "9"
19
+ CYRILLIC_CIS_1 = "10"
20
+ GREEK = "11"
21
+ GREEK_1 = "12"
22
+ GREEK_2 = "13"
23
+ LATIN_1_WINDOWS = "A"
24
+ LATIN_2_WINDOWS = "B"
25
+ CYRILLIC_WINDOWS = "C"
26
+ GREEK_WINDOWS = "D"
27
+ TURKISH_WINDOWS = "E"
28
+ HEBREW_WINDOWS = "F"
29
+
30
+ # 7 bits languages
31
+ USA = "0"
32
+ BRITISH = "1"
33
+ GERMAN = "2"
34
+ FRENCH = "3"
35
+ DANISH = "4"
36
+ ITALIAN = "5"
37
+ SPANISH = "6"
38
+ SWEDISH = "7"
39
+ SWISS = "8"
40
+
41
+ def self.valid_language?(language)
42
+ ("0".."13").include?(language) || ("A".."F").include?(language)
43
+ end
44
+
45
+ def self.validate_language(language)
46
+ raise InvalidLanguageError unless valid_language?(language)
47
+ end
48
+
49
+ def self.validate_language_for_number_of_data_bits(language, number_of_data_bits)
50
+ if number_of_data_bits == 8
51
+ validate_8_data_bits_language language
52
+ elsif number_of_data_bits == 7
53
+ validate_7_data_bits_language language
54
+ else
55
+ raise ArgumentError.new("Unknown number of data bits")
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def self.validate_8_data_bits_language(language)
62
+ raise InvalidLanguageForNumberOfDataBitsError unless [ENGLISH_US,
63
+ LATIN_1, LATIN_2, PORTUGUESE, FRENCH_CANADIAN, NORDIC,
64
+ TURKISH, ICELANDIC, HEBREW, CYRILLIC, CYRILLIC_CIS_1, GREEK,
65
+ GREEK_1, GREEK_2, LATIN_1_WINDOWS, LATIN_2_WINDOWS, CYRILLIC_WINDOWS,
66
+ GREEK_WINDOWS, TURKISH_WINDOWS, HEBREW_WINDOWS].include?(language)
67
+ end
68
+
69
+ def self.validate_7_data_bits_language(language)
70
+ raise InvalidLanguageForNumberOfDataBitsError unless [USA, BRITISH,
71
+ GERMAN, FRENCH, DANISH, ITALIAN, SPANISH, SWEDISH, SWISS].include?(language)
72
+ end
73
+ end
74
+ end
75
+ end
76
+
@@ -0,0 +1,42 @@
1
+ module Zebra
2
+ module Zpl
3
+ module BaseMultiplier
4
+ class InvalidMultiplierError < StandardError; end
5
+
6
+ VALUE_1 = 1
7
+ VALUE_2 = 2
8
+ VALUE_3 = 3
9
+ VALUE_4 = 4
10
+ VALUE_5 = 5
11
+ VALUE_6 = 6
12
+ VALUE_7 = 7
13
+ VALUE_8 = 8
14
+
15
+ def self.included(base_module)
16
+ base_module.instance_eval do
17
+ def validate_multiplier(multiplier)
18
+ raise InvalidMultiplierError unless valid_multiplier?(multiplier)
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ module HorizontalMultiplier
25
+ include BaseMultiplier
26
+
27
+ def self.valid_multiplier?(multiplier)
28
+ (1..8).include? multiplier
29
+ end
30
+ end
31
+
32
+ module VerticalMultiplier
33
+ include BaseMultiplier
34
+
35
+ VALUE_9 = 9
36
+
37
+ def self.valid_multiplier?(multiplier)
38
+ (1..9).include? multiplier
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,18 @@
1
+ module Zebra
2
+ module Zpl
3
+ module PrintMode
4
+ class InvalidPrintModeError < StandardError; end
5
+
6
+ NORMAL = "N"
7
+ REVERSE = "R"
8
+
9
+ def self.valid_mode?(mode)
10
+ %w(N R).include? mode
11
+ end
12
+
13
+ def self.validate_mode(mode)
14
+ raise InvalidPrintModeError unless valid_mode?(mode)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,58 @@
1
+ module Zebra
2
+ module Zpl
3
+ module Printable
4
+ class MissingAttributeError < StandardError
5
+ def initialize(message)
6
+ super("Can't print if #{message}")
7
+ end
8
+ end
9
+
10
+ attr_reader :position, :x, :y, :margin
11
+ attr_accessor :data
12
+
13
+ def initialize(options = {})
14
+ options.each_pair { |attribute, value| self.__send__ "#{attribute}=", value }
15
+ end
16
+
17
+ def position=(coords)
18
+ @position = coords
19
+ @x = (@margin.nil? || @margin == 0) ? coords[0] : (@margin + coords[0])
20
+ @y = coords[1]
21
+ end
22
+
23
+ def justification=(just)
24
+ Justification.validate_justification just
25
+ @justification = just
26
+ end
27
+
28
+ def justification
29
+ @justification || Justification::LEFT
30
+ end
31
+
32
+ def margin=(margin)
33
+ @margin = margin || 0
34
+ end
35
+
36
+ def rotation=(rot)
37
+ Rotation.validate_rotation rot
38
+ @rotation = rot
39
+ end
40
+
41
+ def rotation
42
+ @rotation || Rotation::NO_ROTATION
43
+ end
44
+
45
+ private
46
+
47
+ def has_data?
48
+ true
49
+ end
50
+
51
+ def check_attributes
52
+ raise MissingAttributeError.new("the X value is not given") unless @x
53
+ raise MissingAttributeError.new("the Y value is not given") unless @y
54
+ raise MissingAttributeError.new("the data to be printed is not given") unless @data || !has_data?
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,37 @@
1
+ require "zebra/zpl/printable"
2
+
3
+ module Zebra
4
+ module Zpl
5
+ class Qrcode
6
+ include Printable
7
+
8
+ class InvalidScaleFactorError < StandardError; end
9
+ class InvalidCorrectionLevelError < StandardError; end
10
+
11
+ attr_reader :scale_factor, :correction_level
12
+
13
+ def scale_factor=(value)
14
+ raise InvalidScaleFactorError unless (1..99).include?(value.to_i)
15
+ @scale_factor = value
16
+ end
17
+
18
+ def correction_level=(value)
19
+ raise InvalidCorrectionLevelError unless %w[L M Q H].include?(value.to_s)
20
+ @correction_level = value
21
+ end
22
+
23
+ def to_zpl
24
+ check_attributes
25
+ ["b#{x}", y, "Q", "s#{scale_factor}", "e#{correction_level}", "\"#{data}\""].join(",")
26
+ end
27
+
28
+ private
29
+
30
+ def check_attributes
31
+ super
32
+ raise MissingAttributeError.new("the scale factor to be used is not given") unless @scale_factor
33
+ raise MissingAttributeError.new("the error correction level to be used is not given") unless @correction_level
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,20 @@
1
+ module Zebra
2
+ module Zpl
3
+ module Rotation
4
+ class InvalidRotationError < StandardError; end
5
+
6
+ NO_ROTATION = 'N'
7
+ DEGREES_90 = 'R'
8
+ DEGREES_180 = 'I'
9
+ DEGREES_270 = 'B'
10
+
11
+ def self.valid_rotation?(rotation)
12
+ [NO_ROTATION, DEGREES_90, DEGREES_180, DEGREES_270].include? rotation
13
+ end
14
+
15
+ def self.validate_rotation(rotation)
16
+ raise InvalidRotationError unless valid_rotation?(rotation)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,80 @@
1
+ require "zebra/zpl/printable"
2
+
3
+ module Zebra
4
+ module Zpl
5
+ class Text
6
+ include Printable
7
+
8
+ attr_reader :font_size, :font_type, :width
9
+
10
+ def font_size=(f)
11
+ FontSize.validate_font_size f
12
+ @font_size = f
13
+ end
14
+
15
+ def width=(width)
16
+ unless (margin.nil? || margin < 1)
17
+ @width = (width - (margin*2))
18
+ else
19
+ @width = width || 0
20
+ end
21
+ end
22
+
23
+ def font_type=(type)
24
+ FontType.validate_font_type type
25
+ @font_type = type
26
+ end
27
+
28
+ def font_type
29
+ @font_type || FontType::TYPE_0
30
+ end
31
+
32
+ def print_mode=(mode)
33
+ PrintMode.validate_mode mode
34
+ @print_mode = mode
35
+ end
36
+
37
+ def print_mode
38
+ @print_mode || PrintMode::NORMAL
39
+ end
40
+
41
+ def h_multiplier
42
+ @h_multiplier || HorizontalMultiplier::VALUE_1
43
+ end
44
+
45
+ def v_multiplier
46
+ @v_multiplier || VerticalMultiplier::VALUE_1
47
+ end
48
+
49
+ def print_mode
50
+ @print_mode || PrintMode::NORMAL
51
+ end
52
+
53
+ def h_multiplier=(multiplier)
54
+ HorizontalMultiplier.validate_multiplier multiplier
55
+ @h_multiplier = multiplier
56
+ end
57
+
58
+ def v_multiplier=(multiplier)
59
+ VerticalMultiplier.validate_multiplier multiplier
60
+ @v_multiplier = multiplier
61
+ end
62
+
63
+ def to_zpl
64
+ check_attributes
65
+ # ["A#{x}", y, rotation, font_size, h_multiplier, v_multiplier, print_mode, "\"#{data}\""].join(",")
66
+ # "^FO25,25^FB600,100,0,C,0^FDFoo^FS"
67
+
68
+ # "^CF#{font_type},#{font_size}^FO#{x},#{y}^FB609,4,0,#{justification},0^FD#{data}^FS"
69
+ "^FW#{rotation}^CF#{font_type},#{font_size}^CI28^FO#{x},#{y}^FB#{width},4,0,#{justification},0^FD#{data}^FS"
70
+ end
71
+
72
+ private
73
+
74
+ def check_attributes
75
+ super
76
+ raise MissingAttributeError.new("the font_size to be used is not given") unless @font_size
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,5 @@
1
+ module Zebra
2
+ module Zpl
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
data/lib/zebra/zpl.rb ADDED
@@ -0,0 +1,18 @@
1
+ require "cups"
2
+ require "tempfile"
3
+ require "zebra/zpl/version"
4
+ require "zebra/zpl/language"
5
+ require "zebra/zpl/country_code"
6
+ require "zebra/zpl/character_set"
7
+ require "zebra/zpl/rotation"
8
+ require "zebra/zpl/multipliers"
9
+ require "zebra/zpl/print_mode"
10
+ require "zebra/zpl/font"
11
+ require "zebra/zpl/box"
12
+ require "zebra/zpl/label"
13
+ require "zebra/zpl/text"
14
+ require "zebra/zpl/barcode"
15
+ require "zebra/zpl/barcode_type"
16
+ require "zebra/print_job"
17
+ require "zebra/zpl/qrcode"
18
+ require "zebra/zpl/justification"
@@ -0,0 +1,20 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+
8
+ require "zebra/zpl"
9
+
10
+ RSpec.configure do |config|
11
+ config.treat_symbols_as_metadata_keys_with_true_values = true
12
+ config.run_all_when_everything_filtered = true
13
+ config.filter_run :focus
14
+
15
+ # Run specs in random order to surface order dependencies. If you find an
16
+ # order dependency and want to debug it, you can fix the order by providing
17
+ # the seed, which is printed after each run.
18
+ # --seed 1234
19
+ config.order = 'random'
20
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zebra::PrintJob do
4
+ before do
5
+ Cups.stub(:show_destinations).and_return(["Zebra", "Foobar"])
6
+ end
7
+
8
+ it "receives the name of a printer" do
9
+ described_class.new("Zebra").printer.should == "Zebra"
10
+ end
11
+
12
+ it "raises an error if the printer does not exists" do
13
+ expect {
14
+ described_class.new("Wrong")
15
+ }.to raise_error(Zebra::PrintJob::UnknownPrinter)
16
+ end
17
+
18
+ describe "#print" do
19
+ let(:label) { stub :persist => tempfile }
20
+ let(:cups_job) { stub :print => true }
21
+ let(:tempfile) { stub(:path => "/foo/bar").as_null_object }
22
+
23
+ subject(:print_job) { described_class.new "Zebra" }
24
+
25
+ before { print_job.stub(:` => true) }
26
+
27
+ it "creates a cups print job with the correct arguments" do
28
+ print_job.print label
29
+ end
30
+
31
+ it "prints the label" do
32
+ print_job.should_receive(:`).with("lpr -P Zebra -o raw /foo/bar")
33
+ print_job.print label
34
+ end
35
+ end
36
+ end