label_factory 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: 691b28eda19c88eb8c0f074dac652f0178ebd637
4
+ data.tar.gz: 0360afa4f29142106e5c9c548713515898dc2d3a
5
+ SHA512:
6
+ metadata.gz: bf3367d7084305e573827599dab927d93e47633011d194c6ae6b9b43b93b4f4bc6fb673ad59a19bcf275cc7601f88022a76b6217b566b21b4ee5cc29fb9f4c31
7
+ data.tar.gz: 554c74b041dac1da6eeeb80ee0cff1256aa6d17d5b3c5350e37a236b1e140d10409b55873560986c247fc015037ccc09657bf98e6a0888993f667feda1f974b9
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.pdf
2
+ .rbenv-version
3
+ *.gem
4
+ *.rbc
5
+ .bundle
6
+ .config
7
+ .yardoc
8
+ Gemfile.lock
9
+ InstalledFiles
10
+ _yardoc
11
+ coverage
12
+ doc/
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+ source 'http://gems.github.com'
3
+
4
+ # Specify your gem's dependencies in label_factory.gemspec
5
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 gagoar
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,67 @@
1
+ # LabelFactory
2
+
3
+ create pdf labels with pure ruby
4
+
5
+ you can load your templates in [Glabels](http://www.glabels.org/) format or use the ones that we have already included
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'label_factory'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install label_factory
20
+
21
+ ## Usage
22
+
23
+ this example is taken from tests suit:
24
+
25
+ ``` ruby
26
+ p = LabelFactory::Batch::Base.new("Avery 8160") # label is 2 x 10
27
+ p.draw_boxes(false, true)
28
+ p.add_label("&*\%Positoin 15", position: 15) # should add col 2, row 1
29
+ p.add_label('With Margin', use_margin: true, position: 4)
30
+ p.add_label('No Margin', position: 5, use_margin: false)
31
+ p.add_label('This is the song that never ends, yes it goes on and on my friends', position: 7 )
32
+ p.add_label('X Offset = 4, Y Offset = -6', position: 9, offset_x: 4, offset_y: -6)
33
+ p.add_label('Centered', position: 26, justification: :center) # should add col 2, row 15
34
+ p.add_label('[Right justified]', justification: :right, position: 28) # col 2, row 14, right justified.
35
+ p.add_label('col 2 row 15', position: 29) # should add col 2, row 15
36
+ p.add_label('This was added first and has a BIG font', position: 8, font_size: 16)
37
+ p.add_label('This was added last and has a small font', position: 8, font_size: 8, offset_y: -40)
38
+ p.save_as('labels.pdf')
39
+ ```
40
+
41
+ or multiple lines and fonts per line in a single label!
42
+
43
+ ``` ruby
44
+ pdf = LabelFactory::Batch::Base.new('Avery 8160')
45
+ pdf.draw_boxes(false, false)
46
+ contents = [];
47
+ contents << {text: 'This', justification: :center, font_size: 8, font_type: 'Courier'}
48
+ contents << {text: 'Is a', justification: :right, font_size: 8, font_type: 'Helvetica-BoldOblique'}
49
+ contents << {text: 'Test', font_type: 'Times-Roman'}
50
+ 5.times do |i|
51
+ pdf.add_multiline_label(contents,i)
52
+ end
53
+
54
+ pdf.save_as('other_labels.pdf')
55
+ ```
56
+
57
+ ## Credits
58
+
59
+ this gem is inspirated in [PDF-labels](http://rubyforge.org/projects/pdf-labels/)
60
+
61
+ ## Contributing
62
+
63
+ 1. Fork it
64
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
65
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
66
+ 4. Push to the branch (`git push origin my-new-feature`)
67
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'label_factory/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'label_factory'
8
+ spec.version = LabelFactory::VERSION
9
+ spec.authors = ['gagoar']
10
+ spec.email = ['xeroice@gmail.com']
11
+ spec.description = %q{pdf label creation in ruby}
12
+ spec.summary = %q{http://github.com/eventioz/label_factory}
13
+ spec.homepage = "http://github.com/eventioz/label_factory"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'metaskills-pdf-writer'
22
+ spec.add_dependency 'xml-mapping' , '0.8.1'
23
+
24
+ #development
25
+ spec.add_development_dependency "bundler", ">= 1.3"
26
+ spec.add_development_dependency "rake"
27
+ end
@@ -0,0 +1,248 @@
1
+ module LabelFactory
2
+ module Batch
3
+ class Base
4
+
5
+
6
+ DEFAULTS = { justification: :left, font_size: 12, font_type: 'Helvetica' }
7
+ attr_accessor :template, :label, :pdf, :manual_new_page
8
+ attr_reader :labels_per_page
9
+
10
+ @@gt = nil
11
+
12
+ def initialize(template_name, pdf_opts = {})
13
+
14
+ @template = gt.find_template(template_name)
15
+
16
+ if @template
17
+
18
+ #if the template specifies the paper type, and the user didn't use it.
19
+ pdf_opts[:paper] = @template.size.gsub(/^.*-/,'') if @template.size && !pdf_opts.has_key?(:paper)
20
+
21
+ @label = @template.labels['0']
22
+ @layout = @label.layouts.first
23
+ @labels_per_page = [ @layout.nx, @layout.ny ].reduce(:*)
24
+ @zero_based_labels_per_page = @labels_per_page - 1
25
+
26
+ # set font_dir if needed
27
+ font_dir = pdf_opts.delete(:font_dir)
28
+ PDF::Writer::FONT_PATH << font_dir if font_dir && ! PDF::Writer::FONT_PATH.include?( font_dir )
29
+ # set afm_dir if needed
30
+ afm_dir = pdf_opts.delete(:afm_dir)
31
+ PDF::Writer::FontMetrics::METRICS_PATH << afm_dir if afm_dir && ! PDF::Writer::FontMetrics::METRICS_PATH.include?( font_dir )
32
+
33
+ @pdf = PDF::Writer.new(pdf_opts)
34
+
35
+ @pdf.margins_pt(0, 0, 0, 0)
36
+
37
+ else
38
+ raise 'Template not found!'
39
+ end
40
+ end
41
+
42
+ def self.gt
43
+ @@gt || self.load_template_set
44
+ end
45
+
46
+ def gt
47
+ self.class.gt
48
+ end
49
+
50
+ def self.load_template_set(template_set_file=nil)
51
+ template_set_file ||= File.join(TEMPLATES_PATH, Template::Base::DEFAULT)
52
+ @@gt = Template::Glabel.load_from_file(template_set_file)
53
+ end
54
+
55
+ def self.all_template_names
56
+ gt.all_avaliable_templates
57
+ end
58
+
59
+ def self.all_templates
60
+ gt.templates.values
61
+ end
62
+
63
+ =begin rdoc
64
+ add_label takes an argument hash.
65
+ [:position] Which label slot to print. Positions are top to bottom, left to right so position 1 is the label in the top lefthand corner. Defaults to 0
66
+ [:x & :y] The (x,y) coordinates on the page to print the text. Ignored if position is specified.
67
+ [:text] What you want to print in the label. Defaults to the (x,y) of the top left corner of the label.
68
+ [:use_margin] If the label has a markupMargin, setting this argument to true will respect that margin when writing text. Defaults to true.
69
+ [:justification] Values can be :left, :right, :center, :full. Defaults to :left
70
+ [:offset_x, offset_y] If your printer doesn't want to print with out margins you can define these values to fine tune printout.
71
+ =end
72
+
73
+ def add_label(text, options = {})
74
+ unless options.delete(:skip)
75
+ label_x, label_y, label_width = setup_add_label_options(options)
76
+ opts = setup(label_x, label_width, options)
77
+ @pdf.y = label_y
78
+ end
79
+ opts ||= options
80
+ @pdf.select_font options[:font_type] if options[:font_type]
81
+ text.force_encoding('UTF-8')
82
+ @pdf.text(text, opts)
83
+ opts
84
+ end
85
+
86
+ =begin rdoc
87
+ You can add the same text to many labels this way, takes all the arguments of add_label, but must have position instead of x,y. Requires count.
88
+ [:count] - Number of labels to print
89
+ =end
90
+
91
+ def add_many_labels(text, options = {})
92
+ if !( options[:x] || options[:y] )
93
+ options[:position] ||= 0
94
+ if options[:count]
95
+ options[:count].times do
96
+ add_label(text, options)
97
+ options[:position] += 1
98
+ end
99
+ else
100
+ raise 'Count required'
101
+ end
102
+ else
103
+ raise "Can't use X,Y with add_many_labels, you must use position"
104
+ end
105
+ end
106
+
107
+ =begin rdoc
108
+ we needed something handy to write several lines into a single label, so we provide an array with hashes inside, each hash must contain a [:text] key and
109
+ could contain optional parameters such as :justification, and :font_size if not DEFAULTS options are used.
110
+ =end
111
+ def add_multiline_label(content = [], position = 0)
112
+ opts = {}
113
+ content.each_with_index do |options, i|
114
+ options = DEFAULTS.merge(options)
115
+ if i.zero?
116
+ opts = options
117
+ opts[:position] = position
118
+ else
119
+ opts[:skip] = true
120
+ opts.merge!(options)
121
+ end
122
+ text = opts.delete(:text)
123
+ opts = add_label(text, opts)
124
+ end
125
+ end
126
+
127
+ =begin rdoc
128
+ To facilitate aligning a printer we give a method that prints the outlines of the labels
129
+ =end
130
+ def do_draw_boxes(write_coord = true, draw_markups = true)
131
+ @layout.nx.times do |x|
132
+ @layout.ny.times do |y|
133
+ box_x, box_y = get_x_y(x, y)
134
+ @pdf.rounded_rectangle(box_x,
135
+ box_y,
136
+ @label.width.as_pts,
137
+ @label.height.as_pts,
138
+ @label.round.as_pts).stroke
139
+ if write_coord
140
+ text = "#{box_x / 72}, #{box_y / 72}, #{@label.width.number}, #{label.height.number}"
141
+ add_label(text, x: box_x, y: box_y )
142
+ end
143
+
144
+ if draw_markups
145
+ @label.markupMargins.each do |margin|
146
+ size = margin.size.as_pts
147
+ @pdf.rounded_rectangle(box_x + size,
148
+ box_y - margin.size.as_pts,
149
+ @label.width.as_pts - 2*size,
150
+ @label.height.as_pts - 2*size,
151
+ @label.round.as_pts).stroke
152
+ end
153
+ @label.markupLines.each do |line|
154
+ @pdf.line(box_x + line.x1.as_pts,
155
+ box_y + line.y1.as_pts,
156
+ box_x + line.x2.as_pts,
157
+ box_y + line.y2.as_pts).stroke
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
163
+
164
+ private :do_draw_boxes
165
+
166
+ def draw_boxes(write_coord = true, draw_markups = true)
167
+ pdf.open_object do |heading|
168
+ pdf.save_state
169
+ do_draw_boxes(write_coord, draw_markups)
170
+ pdf.restore_state
171
+ pdf.close_object
172
+ pdf.add_object(heading, :all_pages)
173
+ end
174
+ end
175
+
176
+ def save_as(file_name)
177
+ @pdf.save_as(file_name)
178
+ end
179
+
180
+ protected
181
+
182
+ =begin rdoc
183
+ Position is top to bottom, left to right, starting at 1 and ending at the end of the page
184
+ =end
185
+ def position_to_x_y(position)
186
+ x = (position * 1.0 / @layout.ny).floor
187
+ y = position % @layout.ny
188
+ get_x_y(x, y)
189
+ end
190
+
191
+ def get_x_y(x, y)
192
+ label_y = @pdf.absolute_top_margin
193
+ label_y += @pdf.top_margin
194
+ label_y -= @layout.y0.as_pts
195
+ label_y -= [y, @layout.dy.as_pts].reduce(:*)
196
+
197
+ label_x = @pdf.absolute_left_margin
198
+ label_x -= @pdf.left_margin
199
+ label_x += @layout.x0.as_pts
200
+ label_x += [x, @layout.dx.as_pts ].reduce(:*)
201
+
202
+ [ label_x, label_y ]
203
+ end
204
+
205
+ def setup_add_label_options(options)
206
+ if position = options[:position]
207
+ # condition to handle multi-page PDF generation. If true, we're past the first page
208
+ if position > @zero_based_labels_per_page
209
+ position = position % @labels_per_page
210
+ # if remainder is zero, we're dealing with the first label of a new page
211
+ @pdf.new_page if ( position.zero? && manual_new_page.nil? )
212
+ end
213
+ label_x, label_y = position_to_x_y(position)
214
+ else
215
+ label_x, label_y = position_to_x_y(0) unless ( label_x = options[:x] ) && ( label_y = options[:y] )
216
+ end
217
+
218
+ label_width = label_x + @label.width.as_pts
219
+
220
+ if options[:use_margin].nil?
221
+ @label.markupMargins.each do |margin|
222
+ label_x += margin.size.as_pts
223
+ label_y -= margin.size.as_pts
224
+ label_width -= margin.size.as_pts
225
+ end
226
+ end
227
+
228
+ if options[:offset_x]
229
+ label_x += options[:offset_x]
230
+ label_width += options[:offset_x]
231
+ end
232
+
233
+ label_y += options[:offset_y] if options[:offset_y]
234
+
235
+ [ label_x, label_y, label_width ]
236
+
237
+ end
238
+
239
+ def setup(label_x, label_width, options)
240
+ config = DEFAULTS.merge( { absolute_left: label_x, absolute_right: label_width } )
241
+ config.merge! options
242
+ config.delete(:position)
243
+ config
244
+ end
245
+
246
+ end
247
+ end
248
+ end
@@ -0,0 +1,10 @@
1
+ module LabelFactory
2
+ module Label
3
+ class Alias
4
+ include XML::Mapping
5
+
6
+ text_node :name, '@name'
7
+
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,22 @@
1
+ module LabelFactory
2
+ module Label
3
+ class Base
4
+ include XML::Mapping
5
+
6
+ attr_accessor :shape
7
+
8
+ numeric_node :id, '@id'
9
+
10
+ array_node :markupMargins, 'Markup-margin', class: Layout::Margin, default_value: nil
11
+ array_node :markupCircles, 'Markup-circle', class: Layout::Circle, default_value: nil
12
+ array_node :markupLines, 'Markup-line', class: Layout::Line, default_value: nil
13
+
14
+ array_node :layouts, 'Layout', class: Layout::Base
15
+
16
+ def markups
17
+ @markups ||= [@markupMargins, @markupLines, @markupCircles ].reduce(:merge)
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ module LabelFactory
2
+ module Label
3
+
4
+ class Cd < Base
5
+ length_node :radius, '@radius'
6
+ length_node :waste, '@radius', default_value: '0 pt'
7
+ @kind = 'Round'
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module LabelFactory
2
+ module Label
3
+
4
+ class Rectangle < Base
5
+ length_node :width, '@width'
6
+ length_node :height, '@height'
7
+ length_node :round, '@round', default_value: '0 pt'
8
+ length_node :waste, '@waste', default_value: '0 pt'
9
+ length_node :x_waste, '@x_waste', default_value: '0 pt'
10
+ length_node :y_waste, '@y_waste', default_value: '0 pt'
11
+ @kind = 'Rectangle'
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ module LabelFactory
2
+ module Label
3
+ class Round < Base
4
+
5
+ length_node :radius, '@radius'
6
+ length_node :waste, '@radius', default_value: '0 pt'
7
+ @kind = 'Round'
8
+
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,17 @@
1
+ module LabelFactory
2
+ module Layout
3
+ class Base
4
+
5
+ include XML::Mapping
6
+
7
+ numeric_node :nx, '@nx'
8
+ numeric_node :ny, '@ny'
9
+
10
+ length_node :x0, '@x0', default_value: '0 pt'
11
+ length_node :y0, '@y0', default_value: '0 pt'
12
+ length_node :dx, '@dx', default_value: '0 pt'
13
+ length_node :dy, '@dy', default_value: '0 pt'
14
+ end
15
+ end
16
+ end
17
+
@@ -0,0 +1,11 @@
1
+ module LabelFactory
2
+ module Layout
3
+ class Circle
4
+ include XML::Mapping
5
+
6
+ length_node :x0, '@x0'
7
+ length_node :y0, '@y0'
8
+ length_node :radius, '@radius'
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,33 @@
1
+ module LabelFactory
2
+ module Layout
3
+ class Length
4
+
5
+ attr_accessor :value, :unit, :number
6
+
7
+ def initialize(value)
8
+ @value = value
9
+ @number = value.match(/[\d\.]*/)[0].to_f
10
+ @unit = value.delete("#{number}").strip
11
+ end
12
+
13
+ #Return the numeric portion as a Points
14
+ def as_pts
15
+ if @unit =~ /pt/
16
+ return @number
17
+ elsif @unit =~ /in/
18
+ return @number * 72 #72.270
19
+ elsif @unit =~ /mm/
20
+ return @number * 2.83464566929134
21
+ elsif @unit =~ /cm/
22
+ return @number * 28.3464566929134
23
+ elsif @unit =~ /pc/
24
+ return 1.0 * @number / 12
25
+ elsif @unit == ''
26
+ return @number
27
+ else
28
+ raise "Unit #{unit} unknown"
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,12 @@
1
+ module LabelFactory
2
+ module Layout
3
+ class Line
4
+ include XML::Mapping
5
+
6
+ length_node :x1, '@x1'
7
+ length_node :y1, '@y1'
8
+ length_node :x2, '@x2'
9
+ length_node :y2, '@y2'
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ module LabelFactory
2
+ module Layout
3
+ class Margin
4
+ include XML::Mapping
5
+
6
+ length_node :size, '@size'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,53 @@
1
+ module LabelFactory
2
+ module Template
3
+ class Base
4
+ include XML::Mapping
5
+
6
+ DEFAULT = 'avery-us-templates.xml'
7
+
8
+ attr_accessor :labels
9
+
10
+ text_node :name, '@name'
11
+ text_node :size, '@size'
12
+ text_node :description, '@description', default_value: ''
13
+ text_node :_description, '@_description', default_value: ''
14
+
15
+ length_node :width, '@width', default_value: nil
16
+ length_node :height, '@height', default_value: nil
17
+
18
+ #TODO this could be cleaner, but I'm not sure how yet
19
+ hash_node :rectangles, 'Label-rectangle', '@id', class: Label::Rectangle, default_value: nil
20
+ hash_node :rounds, 'Label-round', '@id', class: Label::Round, default_value: nil
21
+ hash_node :cds, 'Label-cd', '@id', class: Label::Cd, default_value: nil
22
+
23
+ hash_node :alias, 'Alias', '@name', class: Label::Alias, default_value: Hash.new
24
+
25
+ def initialize
26
+
27
+ end
28
+
29
+ def labels
30
+ @labels ||= [ @rectangles, @rounds, @cds ].reduce(:merge)
31
+ end
32
+
33
+ def nx
34
+ first_layout.nx if first_layout
35
+ end
36
+
37
+ def ny
38
+ first_layout.ny if first_layout
39
+ end
40
+
41
+ def find_description
42
+ _description || description
43
+ end
44
+
45
+ private
46
+
47
+ def first_layout
48
+ label = labels['0']
49
+ label.layouts.first if label
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,32 @@
1
+ module LabelFactory
2
+ module Template
3
+ class Glabel
4
+ include XML::Mapping
5
+
6
+ hash_node :templates, 'Template', '@name', class: Base, default_value: Hash.new
7
+
8
+ def find_all_templates
9
+ unless @templates
10
+ @templates = []
11
+ templates.each do |template|
12
+ template = template[1]
13
+ @templates << template.name
14
+ template.alias.each do |aliases|
15
+ @templates << aliases[1].name
16
+ end
17
+ end
18
+ end
19
+ @templates
20
+ end
21
+
22
+ def find_template(template_name)
23
+ template = templates.find{|k,v| k == template_name || v.alias[template_name]}
24
+ template[1] if template
25
+ end
26
+
27
+ def all_avaliable_templates
28
+ templates.values.map(&:name) + templates.values.map(&:alias).map(&:keys).flatten
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,22 @@
1
+ module LabelFactory
2
+ module Util
3
+ class LengthNode < XML::Mapping::SingleAttributeNode
4
+
5
+ def initialize_impl(path)
6
+ @path = XML::XXPath.new(path)
7
+ end
8
+
9
+ def extract_attr_value(xml)
10
+ @value = default_when_xpath_err{@path.first(xml).text}
11
+ Layout::Length.new(@value)
12
+ end
13
+
14
+ def set_attr_value(xml, value)
15
+ raise "Not a Length: #{value}" unless value.is_a? Layout::Length
16
+ @path.first(xml, ensure_created: true).text = value.value
17
+ end
18
+ end
19
+
20
+ XML::Mapping.add_node_class LengthNode
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module LabelFactory
2
+ VERSION = '1.0.0'
3
+ end