label_factory 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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