eaglecad 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/Gemfile +5 -1
- data/README.markdown +29 -0
- data/Rakefile +9 -0
- data/eaglecad.gemspec +4 -2
- data/lib/eaglecad.rb +15 -1
- data/lib/eaglecad/attribute.rb +47 -0
- data/lib/eaglecad/board.rb +184 -0
- data/lib/eaglecad/clearance.rb +31 -0
- data/lib/eaglecad/design_rules.rb +38 -0
- data/lib/eaglecad/deviceset.rb +113 -0
- data/lib/eaglecad/drawing.rb +124 -0
- data/lib/eaglecad/geometry.rb +259 -0
- data/lib/eaglecad/layer.rb +40 -0
- data/lib/eaglecad/library.rb +73 -0
- data/lib/eaglecad/package.rb +74 -0
- data/lib/eaglecad/part.rb +29 -0
- data/lib/eaglecad/schematic.rb +83 -0
- data/lib/eaglecad/sheet.rb +256 -0
- data/lib/eaglecad/symbol.rb +73 -0
- data/test/eaglecad.rb +12 -0
- data/test/eaglecad/board.rb +68 -0
- data/test/eaglecad/design_rules.rb +38 -0
- data/test/eaglecad/deviceset.rb +52 -0
- data/test/eaglecad/drawing.rb +94 -0
- data/test/eaglecad/library.rb +47 -0
- data/test/eaglecad/package.rb +60 -0
- data/test/eaglecad/schematic.rb +50 -0
- data/test/eaglecad/sheet.rb +24 -0
- data/test/eaglecad/symbol.rb +41 -0
- data/test/fixtures/board.xml +859 -0
- data/test/fixtures/demo1.sch +10932 -0
- data/test/fixtures/design_rules.xml +70 -0
- data/test/fixtures/deviceset.xml +683 -0
- data/test/fixtures/drawing_board.xml +910 -0
- data/test/fixtures/drawing_schematic.xml +10928 -0
- data/test/fixtures/hexapodu.brd +1863 -0
- data/test/fixtures/library.xml +175 -0
- data/test/fixtures/package.xml +28 -0
- data/test/fixtures/schematic.xml +10861 -0
- data/test/fixtures/sheet.xml +318 -0
- data/test/fixtures/symbol.xml +11 -0
- metadata +79 -5
- data/README.md +0 -29
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
|
3
|
+
require_relative 'geometry'
|
4
|
+
|
5
|
+
module EagleCAD
|
6
|
+
Point = ::Geometry::Point
|
7
|
+
Size = ::Geometry::Size
|
8
|
+
|
9
|
+
class Package
|
10
|
+
attr_accessor :name, :description
|
11
|
+
attr_reader :holes, :layers, :pads
|
12
|
+
|
13
|
+
# Create a new {Package} from an {REXML::Element}
|
14
|
+
# @param [REXML::Element] element The {REXML::Element} to parse
|
15
|
+
def self.from_xml(element)
|
16
|
+
package = Package.new element.attributes['name']
|
17
|
+
|
18
|
+
element.elements.each do |element|
|
19
|
+
layer_number = element.attributes['layer'].to_i if element.attributes.has_key?('layer')
|
20
|
+
case element.name
|
21
|
+
when 'description'
|
22
|
+
package.description = element.text
|
23
|
+
when 'hole'
|
24
|
+
package.holes.push Geometry::Hole.from_xml(element)
|
25
|
+
when 'pad'
|
26
|
+
package.pads.push Geometry::Pad.from_xml(element)
|
27
|
+
else
|
28
|
+
g = Geometry.from_xml(element)
|
29
|
+
if g
|
30
|
+
package.push layer_number, g
|
31
|
+
else
|
32
|
+
raise StandardError, "Unrecognized package element '#{element.name}'"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
package
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param [String] name The name of the {Package}
|
41
|
+
def initialize(name)
|
42
|
+
@holes = []
|
43
|
+
@layers = {}
|
44
|
+
@layers.default_proc = proc {|hash, key| hash[key] = []}
|
45
|
+
@name = name
|
46
|
+
@pads = []
|
47
|
+
end
|
48
|
+
|
49
|
+
# Push a new element to the given layer number
|
50
|
+
# @param [Numeric] layer_number The layer to add the element to
|
51
|
+
# @param [Object] element The thing to push
|
52
|
+
def push(layer_number, element)
|
53
|
+
layer = @layers[layer_number]
|
54
|
+
layer.push element
|
55
|
+
end
|
56
|
+
|
57
|
+
# Generate XML for the {Package} element
|
58
|
+
# @return [REXML::Element]
|
59
|
+
def to_xml
|
60
|
+
REXML::Element.new('package').tap do |element|
|
61
|
+
element.add_attribute('name', name)
|
62
|
+
element.add_element('description').text = description
|
63
|
+
|
64
|
+
holes.each {|hole| element.add_element hole.to_xml }
|
65
|
+
pads.each {|pad| element.add_element pad.to_xml }
|
66
|
+
|
67
|
+
layers.each do |number, layer|
|
68
|
+
layer.each {|obj| element.add_element(obj.to_xml, {'layer' => number}) }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
|
3
|
+
module EagleCAD
|
4
|
+
class Part
|
5
|
+
attr_accessor :name, :library, :deviceset, :device, :technology, :value
|
6
|
+
|
7
|
+
def self.from_xml(element)
|
8
|
+
Part.new(element.attributes['name'], element.attributes['library'], element.attributes['deviceset'], element.attributes['device']).tap do |part|
|
9
|
+
part.technology = element.attributes['technology'] if element.attributes['technology']
|
10
|
+
part.value = element.attributes['value'] if element.attributes['value']
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(name, library, deviceset, device)
|
15
|
+
@name = name
|
16
|
+
@library = library
|
17
|
+
@deviceset = deviceset
|
18
|
+
@device = device
|
19
|
+
@technology = ''
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_xml
|
23
|
+
REXML::Element.new('part').tap do |element|
|
24
|
+
element.add_attributes({'name' => name, 'library' => library, 'deviceset' => deviceset, 'device' => device, 'technology' => technology})
|
25
|
+
element.add_attribute('value', value) if value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
|
3
|
+
require_relative 'attribute'
|
4
|
+
require_relative 'clearance'
|
5
|
+
require_relative 'geometry'
|
6
|
+
require_relative 'library'
|
7
|
+
require_relative 'part'
|
8
|
+
require_relative 'sheet'
|
9
|
+
|
10
|
+
module EagleCAD
|
11
|
+
class Schematic
|
12
|
+
attr_accessor :description
|
13
|
+
attr_reader :attributes, :classes, :libraries, :parts, :sheets
|
14
|
+
|
15
|
+
# Create a new {Schematic} from an {REXML::Element}
|
16
|
+
# @param [REXML::Element] element The {REXML::Element} to parse
|
17
|
+
def self.from_xml(element)
|
18
|
+
Schematic.new.tap do |schematic|
|
19
|
+
element.elements.each do |element|
|
20
|
+
case element.name
|
21
|
+
when 'attributes'
|
22
|
+
element.elements.each {|attribute| schematic.attributes.push Attribute.from_xml(attribute) }
|
23
|
+
when 'classes'
|
24
|
+
element.elements.each {|clearance| schematic.classes.push Clearance.from_xml(clearance) }
|
25
|
+
when 'description'
|
26
|
+
schematic.description = element.text
|
27
|
+
when 'libraries'
|
28
|
+
element.elements.each {|library| schematic.libraries[library.attributes['name']] = Library.from_xml(library) }
|
29
|
+
when 'parts'
|
30
|
+
element.elements.each {|part| schematic.parts.push Part.from_xml(part) }
|
31
|
+
when 'sheets'
|
32
|
+
element.elements.each {|sheet| schematic.sheets.push Sheet.from_xml(sheet) }
|
33
|
+
when 'variantdefs'
|
34
|
+
else
|
35
|
+
raise StandardError, "Unrecognized element '#{element.name}'"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize
|
42
|
+
@attributes = []
|
43
|
+
@classes = []
|
44
|
+
@libraries = {}
|
45
|
+
@parts = []
|
46
|
+
@sheets = []
|
47
|
+
end
|
48
|
+
|
49
|
+
# Generate XML for the {Schematic} element
|
50
|
+
# @return [REXML::Element]
|
51
|
+
def to_xml
|
52
|
+
REXML::Element.new('schematic').tap do |element|
|
53
|
+
element.add_element('description').text = description if description
|
54
|
+
|
55
|
+
# Libraries must be output before parts or Eagle will fail to load the file
|
56
|
+
element.add_element('libraries').tap do |libraries_element|
|
57
|
+
libraries.each do |name, library|
|
58
|
+
libraries_element.add_element library.to_xml
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
REXML::Element.new('attributes').tap do |attributes_element|
|
63
|
+
attributes.each {|attribute| attributes_element.add_element attribute.to_xml }
|
64
|
+
element.add_element(attributes_element) if attributes_element.has_elements?
|
65
|
+
end
|
66
|
+
|
67
|
+
element.add_element('variantdefs')
|
68
|
+
|
69
|
+
element.add_element('classes').tap do |classes_element|
|
70
|
+
classes.each {|object| classes_element.add_element object.to_xml }
|
71
|
+
end
|
72
|
+
|
73
|
+
element.add_element('parts').tap do |parts_element|
|
74
|
+
parts.each {|part| parts_element.add_element part.to_xml }
|
75
|
+
end
|
76
|
+
|
77
|
+
element.add_element('sheets').tap do |sheets_element|
|
78
|
+
sheets.each {|sheet| sheets_element.add_element sheet.to_xml }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,256 @@
|
|
1
|
+
require_relative 'attribute'
|
2
|
+
require_relative 'geometry'
|
3
|
+
|
4
|
+
module EagleCAD
|
5
|
+
class Sheet
|
6
|
+
attr_accessor :description
|
7
|
+
attr_reader :busses, :instances, :nets
|
8
|
+
|
9
|
+
PinReference = Struct.new :part, :gate, :pin do
|
10
|
+
def self.from_xml(element)
|
11
|
+
Sheet::PinReference.new element.attributes['part'], element.attributes['gate'], element.attributes['pin']
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_xml
|
15
|
+
REXML::Element.new('pinref').tap do |element|
|
16
|
+
element.add_attributes('gate' => gate, 'part' => part, 'pin' => pin)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Bus
|
22
|
+
attr_accessor :name
|
23
|
+
attr_reader :segments
|
24
|
+
|
25
|
+
def self.from_xml(element)
|
26
|
+
Bus.new(element.attributes['name']).tap do |bus|
|
27
|
+
element.elements.each {|segment| bus.segments.push Segment.from_xml(segment) }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(name)
|
32
|
+
@name = name
|
33
|
+
@segments = []
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_xml
|
37
|
+
REXML::Element.new('bus').tap do |element|
|
38
|
+
element.add_attribute 'name', name
|
39
|
+
segments.each {|segment| element.add_element segment.to_xml }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Instance
|
45
|
+
attr_accessor :part, :gate, :origin, :smashed, :rotation
|
46
|
+
attr_reader :attributes
|
47
|
+
|
48
|
+
def self.from_xml(element)
|
49
|
+
Instance.new(element.attributes['part'], element.attributes['gate'], Geometry.point_from(element)).tap do |instance|
|
50
|
+
element.attributes.each do |name, value|
|
51
|
+
case name
|
52
|
+
when 'smashed' then instance.smashed = ('no' != element.attributes['smashed'])
|
53
|
+
when 'rot' then instance.rotation = element.attributes['rot']
|
54
|
+
when 'part', 'gate', 'x', 'y' # Ignore; already handled
|
55
|
+
else
|
56
|
+
raise StandardError, "Unrecognized Instance attribute '#{name}'"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
element.elements.each {|attribute| instance.attributes.push Attribute.from_xml(attribute) }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def initialize(part, gate, origin)
|
65
|
+
@attributes = []
|
66
|
+
@part = part
|
67
|
+
@gate = gate
|
68
|
+
@origin = origin
|
69
|
+
@smashed = false
|
70
|
+
@rotation = 'R0'
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_xml
|
74
|
+
REXML::Element.new('instance').tap do |element|
|
75
|
+
element.add_attributes({'part' => part, 'gate' => gate, 'x' => origin.x, 'y' => origin.y})
|
76
|
+
element.add_attribute('smashed', 'yes') if smashed
|
77
|
+
element.add_attribute('rot', rotation)
|
78
|
+
|
79
|
+
attributes.each {|attribute| element.add_element attribute.to_xml }
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class Label
|
85
|
+
attr_accessor :origin, :size, :layer_number, :font, :ratio, :rotation, :cross_reference
|
86
|
+
|
87
|
+
def self.from_xml(element)
|
88
|
+
Label.new(Geometry.point_from(element), element.attributes['size'].to_f, element.attributes['layer'].to_i).tap do |label|
|
89
|
+
element.attributes.each do |name, value|
|
90
|
+
case name
|
91
|
+
when 'font' then label.font = value.to_sym
|
92
|
+
when 'ratio' then label.ratio = value.to_i
|
93
|
+
when 'rot' then label.rotation = value
|
94
|
+
when 'xref' then label.cross_reference = ('no' != value)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def initialize(origin, size, layer_number)
|
101
|
+
@origin = origin
|
102
|
+
@size = size
|
103
|
+
@layer_number = layer_number
|
104
|
+
@font = :proportional
|
105
|
+
@ratio = 8
|
106
|
+
@rotation = 'R0'
|
107
|
+
@cross_reference = false
|
108
|
+
end
|
109
|
+
|
110
|
+
def to_xml
|
111
|
+
REXML::Element.new('label').tap do |element|
|
112
|
+
element.add_attributes({'x' => origin.x, 'y' => origin.y, 'layer' => layer_number ,'size' => size})
|
113
|
+
element.add_attribute('font', font)
|
114
|
+
element.add_attribute('ratio', ratio) unless 8 == ratio
|
115
|
+
element.add_attribute('rot', rotation)
|
116
|
+
element.add_attribute('xref', cross_reference) if cross_reference
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
class Net
|
122
|
+
attr_accessor :clearance_class, :name
|
123
|
+
attr_reader :segments
|
124
|
+
|
125
|
+
def self.from_xml(element)
|
126
|
+
Net.new(element.attributes['name'], element.attributes['class'].to_i).tap do |net|
|
127
|
+
element.elements.each {|segment| net.segments.push Segment.from_xml(segment) }
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def initialize(name, clearance_class)
|
132
|
+
@clearance_class = clearance_class
|
133
|
+
@name = name
|
134
|
+
@segments = []
|
135
|
+
end
|
136
|
+
|
137
|
+
def to_xml
|
138
|
+
REXML::Element.new('net').tap do |element|
|
139
|
+
element.add_attribute('name', name)
|
140
|
+
element.add_attribute('class', clearance_class) unless 0 == clearance_class
|
141
|
+
|
142
|
+
segments.each {|segment| element.add_element segment.to_xml }
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
class Segment
|
148
|
+
attr_reader :elements, :layers
|
149
|
+
|
150
|
+
def self.from_xml(element)
|
151
|
+
Segment.new.tap do |segment|
|
152
|
+
element.elements.each do |element|
|
153
|
+
case element.name
|
154
|
+
when 'junction'
|
155
|
+
segment.elements.push Geometry.point_from(element)
|
156
|
+
when 'label'
|
157
|
+
segment.push element.attributes['layer'], Label.from_xml(element)
|
158
|
+
when 'pinref'
|
159
|
+
segment.elements.push PinReference.from_xml(element)
|
160
|
+
when 'wire'
|
161
|
+
segment.push element.attributes['layer'], Geometry::Line.from_xml(element)
|
162
|
+
else
|
163
|
+
raise StandardError, "Unrecognized Segment element '#{element.name}"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def initialize
|
170
|
+
@elements = []
|
171
|
+
@layers = {}
|
172
|
+
@layers.default_proc = proc {|hash, key| hash[key] = []}
|
173
|
+
end
|
174
|
+
|
175
|
+
# Push a new element to the given layer number
|
176
|
+
# @param [Numeric] layer_number The layer to add the element to
|
177
|
+
# @param [Object] element The thing to push
|
178
|
+
def push(layer_number, element)
|
179
|
+
layer = @layers[layer_number]
|
180
|
+
layer.push element
|
181
|
+
end
|
182
|
+
|
183
|
+
def to_xml
|
184
|
+
REXML::Element.new('segment').tap do |element|
|
185
|
+
elements.each do |object|
|
186
|
+
if object.is_a? Point
|
187
|
+
element.add_element('junction', {'x' => object.x, 'y' => object.y})
|
188
|
+
else
|
189
|
+
element.add_element object.to_xml
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
layers.each do |number, layer|
|
194
|
+
layer.each {|obj| element.add_element(obj.to_xml, {'layer' => number}) }
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def self.from_xml(element)
|
201
|
+
Sheet.new.tap do |sheet|
|
202
|
+
element.elements.each do |element|
|
203
|
+
case element.name
|
204
|
+
when 'busses'
|
205
|
+
element.elements.each {|bus| sheet.push Bus.from_xml(bus) }
|
206
|
+
when 'description'
|
207
|
+
sheet.description = element.text
|
208
|
+
when 'instances'
|
209
|
+
element.elements.each {|instance| sheet.push Instance.from_xml(instance) }
|
210
|
+
when 'nets'
|
211
|
+
element.elements.each {|part| sheet.push Net.from_xml(part) }
|
212
|
+
when 'plain' #Ignore
|
213
|
+
else
|
214
|
+
raise StandardError, "Unrecognized Sheet element '#{element.name}'"
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def initialize
|
221
|
+
@busses = []
|
222
|
+
@instances = []
|
223
|
+
@nets = []
|
224
|
+
@parts = []
|
225
|
+
end
|
226
|
+
|
227
|
+
# Add the passed {Sheet} element to the {Sheet}
|
228
|
+
def push(arg)
|
229
|
+
case arg
|
230
|
+
when Bus then busses.push arg
|
231
|
+
when Instance then instances.push arg
|
232
|
+
when Net then nets.push arg
|
233
|
+
else
|
234
|
+
raise ArgumentError, "Unrecognized object '#{arg.class}'"
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def to_xml
|
239
|
+
REXML::Element.new('sheet').tap do |element|
|
240
|
+
element.add_element('description').text = description
|
241
|
+
|
242
|
+
element.add_element('instances').tap do |instances_element|
|
243
|
+
instances.each {|instance| instances_element.add_element instance.to_xml }
|
244
|
+
end
|
245
|
+
|
246
|
+
element.add_element('busses').tap do |busses_element|
|
247
|
+
busses.each {|bus| busses_element.add_element bus.to_xml }
|
248
|
+
end
|
249
|
+
|
250
|
+
element.add_element('nets').tap do |nets_element|
|
251
|
+
nets.each {|net| nets_element.add_element net.to_xml }
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
|
3
|
+
require_relative 'geometry'
|
4
|
+
|
5
|
+
module EagleCAD
|
6
|
+
class Symbol
|
7
|
+
attr_accessor :name, :description
|
8
|
+
attr_reader :layers, :pins
|
9
|
+
|
10
|
+
# Create a new {Symbol} from an {REXML::Element}
|
11
|
+
# @param [Element] element The {REXML::Element} to parse
|
12
|
+
def self.from_xml(element)
|
13
|
+
symbol = Symbol.new element.attributes['name']
|
14
|
+
|
15
|
+
element.elements.each do |element|
|
16
|
+
layer_number = element.attributes['layer'].to_i if element.attributes.has_key?('layer')
|
17
|
+
case element.name
|
18
|
+
when 'circle'
|
19
|
+
symbol.push layer_number, Geometry::Circle.from_xml(element)
|
20
|
+
when 'description'
|
21
|
+
symbol.description = element.text
|
22
|
+
when 'pin'
|
23
|
+
symbol.pins.push Geometry::Pin.from_xml(element)
|
24
|
+
when 'polygon'
|
25
|
+
symbol.push layer_number, Geometry::Polygon.from_xml(element)
|
26
|
+
when 'rectangle'
|
27
|
+
symbol.push layer_number, Geometry::Rectangle.from_xml(element)
|
28
|
+
when 'smd'
|
29
|
+
symbol.push layer_number, Geometry::SMD.from_xml(element)
|
30
|
+
when 'text'
|
31
|
+
symbol.push layer_number, Geometry::Text.from_xml(element)
|
32
|
+
when 'wire'
|
33
|
+
symbol.push layer_number, Geometry::Line.from_xml(element)
|
34
|
+
else
|
35
|
+
raise StandardError, "Unrecognized symbol element '#{element.name}'"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
symbol
|
40
|
+
end
|
41
|
+
|
42
|
+
# @param [String] name The name of the {Package}
|
43
|
+
def initialize(name)
|
44
|
+
@layers = {}
|
45
|
+
@layers.default_proc = proc {|hash, key| hash[key] = []}
|
46
|
+
@name = name
|
47
|
+
@pins = []
|
48
|
+
end
|
49
|
+
|
50
|
+
# Push a new element to the given layer number
|
51
|
+
# @param [Numeric] layer_number The layer to add the element to
|
52
|
+
# @param [Object] element The thing to push
|
53
|
+
def push(layer_number, element)
|
54
|
+
layer = @layers[layer_number]
|
55
|
+
layer.push element
|
56
|
+
end
|
57
|
+
|
58
|
+
# Generate XML for the {Symbol} element
|
59
|
+
# @return [REXML::Element]
|
60
|
+
def to_xml
|
61
|
+
REXML::Element.new('symbol').tap do |element|
|
62
|
+
element.add_attribute 'name', name
|
63
|
+
element.add_element('description').text = description if description
|
64
|
+
|
65
|
+
pins.each {|pin| element.add_element pin.to_xml }
|
66
|
+
|
67
|
+
layers.each do |number, layer|
|
68
|
+
layer.each {|obj| element.add_element(obj.to_xml, {'layer' => number}) }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|