ruby-gdsii 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/LICENSE.txt +20 -0
  2. data/README.txt +113 -0
  3. data/bin/rgds-debug +43 -0
  4. data/bin/rgds-dump +38 -0
  5. data/bin/rgds-join +98 -0
  6. data/bin/rgds-layers +53 -0
  7. data/bin/rgds-sremove +135 -0
  8. data/bin/rgds-ssplit +113 -0
  9. data/bin/rgds-stats +134 -0
  10. data/bin/rgds-structs +41 -0
  11. data/bin/rgds-tree +166 -0
  12. data/bin/rgds2rb +99 -0
  13. data/lib/gdsii.rb +137 -0
  14. data/lib/gdsii/aref.rb +243 -0
  15. data/lib/gdsii/bnf.rb +309 -0
  16. data/lib/gdsii/boundary.rb +53 -0
  17. data/lib/gdsii/box.rb +65 -0
  18. data/lib/gdsii/byte_order.rb +36 -0
  19. data/lib/gdsii/element.rb +172 -0
  20. data/lib/gdsii/group.rb +98 -0
  21. data/lib/gdsii/library.rb +518 -0
  22. data/lib/gdsii/mixins.rb +378 -0
  23. data/lib/gdsii/node.rb +65 -0
  24. data/lib/gdsii/path.rb +169 -0
  25. data/lib/gdsii/property.rb +108 -0
  26. data/lib/gdsii/record.rb +606 -0
  27. data/lib/gdsii/record/consts.rb +384 -0
  28. data/lib/gdsii/record/datatypes/ascii.rb +145 -0
  29. data/lib/gdsii/record/datatypes/bitarray.rb +101 -0
  30. data/lib/gdsii/record/datatypes/data.rb +111 -0
  31. data/lib/gdsii/record/datatypes/int2.rb +67 -0
  32. data/lib/gdsii/record/datatypes/int4.rb +65 -0
  33. data/lib/gdsii/record/datatypes/nodata.rb +60 -0
  34. data/lib/gdsii/record/datatypes/real4.rb +51 -0
  35. data/lib/gdsii/record/datatypes/real8.rb +120 -0
  36. data/lib/gdsii/sref.rb +61 -0
  37. data/lib/gdsii/strans.rb +133 -0
  38. data/lib/gdsii/structure.rb +352 -0
  39. data/lib/gdsii/text.rb +203 -0
  40. data/pkg/ruby-gdsii.gem +23 -0
  41. data/samples/hello.gds +0 -0
  42. data/samples/hello.out.rb +84 -0
  43. data/samples/hello.rb +94 -0
  44. data/test/baseline/dcp1.gds +0 -0
  45. data/test/baseline/h_write.gds +0 -0
  46. data/test/h_pthru.rb +22 -0
  47. data/test/h_write.rb +117 -0
  48. data/test/hs_pthru.rb +31 -0
  49. data/test/l_pthru.rb +23 -0
  50. data/test/test_gds_group.rb +379 -0
  51. data/test/test_gds_record.rb +99 -0
  52. metadata +118 -0
@@ -0,0 +1,309 @@
1
+ require 'gdsii/record/consts'
2
+
3
+ module Gdsii
4
+
5
+ #
6
+ # Class to hold BNF items which are to be listed in the BnfSpec class. The
7
+ # BnfItem objects are used to indicate the unique BNF key and also whether
8
+ # or not it is optional and whether or not it is multiple.
9
+ #
10
+ class BnfItem
11
+
12
+ attr_reader :key, :optional, :multiple
13
+
14
+ #
15
+ # Create a new BNF item of a given key and specify if it is optional
16
+ # and if there are multiple values. The key is either one of the
17
+ # Gdsii::GRT_* constants or is a class descended from Gdsii::Group.
18
+ # Examples:
19
+ #
20
+ # BnfItem.new(Property,true,true),
21
+ # BnfItem.new(GRT_ENDEL)
22
+ #
23
+ def initialize(key, optional=false, multiple=false)
24
+ @key = key
25
+ @optional = optional
26
+ @multiple = multiple
27
+ end
28
+
29
+ #
30
+ # True if this BNF item is optional; false if not (opposite of #required?)
31
+ #
32
+ def optional?() @optional; end
33
+
34
+ #
35
+ # True if this BNF item has multiple values; false if not
36
+ #
37
+ def multiple?() @multiple; end
38
+
39
+ #
40
+ # Dump the name for this BNF item
41
+ #
42
+ def to_s(); Gdsii::grt_name(@key); end
43
+
44
+ #
45
+ # (hide from RDoc) - Add details to inspect
46
+ #
47
+ def inspect() # :nodoc:
48
+ "#<#{self.class}:0x#{sprintf("%x", self.object_id*2)} == #{self.to_s}>"
49
+ end
50
+
51
+ end
52
+
53
+ ############################################################################
54
+
55
+ #
56
+ # This class represents the order of a GDSII record grouping using a specific
57
+ # record order in Backus-Naur Form (BNF). It consists of a number of BnfItem
58
+ # objects where the order of the items is important in determining the order
59
+ # in which the GDSII file format should be read or written from/to a file.
60
+ #
61
+ class BnfSpec
62
+
63
+ include Enumerable
64
+
65
+ attr_reader :bnf_items
66
+
67
+ #
68
+ # Creates a Backus-Naur Form (BNF) grouping consisting of BnfItem objects.
69
+ #
70
+ # spec = BnfSpec.new(
71
+ # BnfItem.new(GRT_PROPATTR),
72
+ # BnfItem.new(GRT_PROPVALUE)
73
+ # )
74
+ #
75
+ def initialize(*bnf_items)
76
+ @bnf_items = bnf_items
77
+ end
78
+
79
+ #
80
+ # Loops through each BnfItem in this BnfSpec yielding the BnfItem along
81
+ # the way.
82
+ #
83
+ # spec.each {|bnf_item| ...}
84
+ #
85
+ def each()
86
+ @bnf_items.each {|bnf_item| yield bnf_item}
87
+ end
88
+ alias :each_item :each
89
+
90
+ #
91
+ # Finds a BnfItem of a given key in this Bnf object or nil if one is not
92
+ # found.
93
+ #
94
+ # spec = ...
95
+ # spec.find_item(GRT_PROPATTR) #=> BnfItem ...
96
+ # spec.find_item(GRT_HEADER) #=> nil
97
+ #
98
+ def find_item(key)
99
+ @bnf_items.find {|bnf_item| bnf_item.key == key}
100
+ end
101
+
102
+ #
103
+ # Shortcut for #find_item but will raise an exception if the item key
104
+ # is not part of this BNF.
105
+ #
106
+ # spec = ...
107
+ # spec.find_item(GRT_PROPATTR) #=> BnfItem ...
108
+ # spec.find_item(GRT_HEADER) #=> raise IndexError ...
109
+ #
110
+ def [](key)
111
+ if (found = find_item(key))
112
+ found
113
+ else
114
+ raise IndexError, "Cannot find BnfItem of key #{Gdsii::grt_name(key)} in BNF"
115
+ end
116
+ end
117
+
118
+ #
119
+ # Format for inspection
120
+ #
121
+ def inspect() # :nodoc:
122
+ "#<#{self.class}:0x#{sprintf("%x", self.object_id*2)}:@bnf_items.map {|i| i.to_s}.inspect>"
123
+ end
124
+
125
+ end
126
+
127
+ ############################################################################
128
+
129
+ #
130
+ # Used to store records for a record grouping (i.e. classes descending
131
+ # from Group). Only records that are in the BnfSpec may be added.
132
+ #
133
+ class BnfRecords
134
+
135
+ #
136
+ # Create a new BnfRecords object. The parent class is stored so that
137
+ # entries may be compared against the BnfSpec.
138
+ #
139
+ def initialize(parent_class)
140
+ @parent_class = parent_class
141
+ @bnf_records = {}
142
+ end
143
+
144
+ #
145
+ # Returns the BnfSpec of the parent class.
146
+ #
147
+ def bnf_spec()
148
+ @parent_class.bnf_spec
149
+ end
150
+
151
+ #
152
+ # Returns the BNF record keys that exist in this grouping of BNF records.
153
+ #
154
+ def bnf_keys()
155
+ @bnf_records.keys
156
+ end
157
+
158
+ #
159
+ # Retrieves the Record for a given BNF item key. If the record is
160
+ # multiple according to the BNF description, then an array of
161
+ # Record objects is returned. Used internally by various grouping accessor
162
+ # methods.
163
+ #
164
+ def get(key)
165
+ bnf_item = bnf_spec[key]
166
+ if bnf_item.multiple?
167
+ @bnf_records[key] = [] unless @bnf_records.has_key? key
168
+ @bnf_records[key]
169
+ else
170
+ if key.class == Class and @bnf_records[key].nil?
171
+ @bnf_records[key] = key.new
172
+ end
173
+ @bnf_records[key]
174
+ end
175
+ end
176
+
177
+ alias :[] :get
178
+
179
+ #
180
+ # Retrieves the Record *data* (i.e value) for a given BNF item key. If
181
+ # the record is multiple according to the BNF description, then an array
182
+ # of Record data is returned. Used internally by various grouping accessor
183
+ # methods.
184
+ #
185
+ def get_data(key)
186
+ if bnf_spec[key].multiple?
187
+ get(key).map {|record| record.data_value}
188
+ else
189
+ ((record = get(key)).nil?) ? nil : record.data_value
190
+ end
191
+ end
192
+
193
+ #
194
+ # Sets the record data for a given BNF item key. The value may be the
195
+ # of the class to be added or can be a raw value which is automatically
196
+ # coerced into the proper class for the given key. Used internally by
197
+ # various grouping accessor methods. Returns the object being set.
198
+ #
199
+ def set(key, value)
200
+ if key.class == Class
201
+ @bnf_records[key] = value
202
+ elsif value.nil?
203
+ @bnf_records[key] = value
204
+ else
205
+ value = coerce_record_value(key, value)
206
+ value = [value] if bnf_spec[key].multiple? and value.class != Array
207
+ @bnf_records[key] = value
208
+ end
209
+ end
210
+
211
+ alias :[]= :set
212
+
213
+ #
214
+ # Adds the record or record value to the bnf_records hash (applicable only
215
+ # for records with multiple entries). Returns the updated list of values.
216
+ # Used internally by various grouping accessor methods. Returns the object
217
+ # being set.
218
+ #
219
+ def add(key, value)
220
+ if bnf_spec[key].multiple?
221
+ value = coerce_record_value(key, value)
222
+ get(key).push value
223
+ else
224
+ raise TypeError, "BNF for key #{key} is singular in class #{parent_class}; use #set instead"
225
+ end
226
+ end
227
+
228
+ #
229
+ # Accepts a code block which should return true or false. If the return
230
+ # value is true, then the value meeting the criteria is removed. This
231
+ # is used internally by various grouping accessor methods. Note, this is
232
+ # only applicable for records with multiple values.
233
+ #
234
+ # object.reject!(Property) {|property|
235
+ # property.attr == 1
236
+ # }
237
+ #
238
+ def reject!(key)
239
+ if bnf_spec[key].multiple?
240
+ @bnf_records[key].reject! {|value| yield value}
241
+ else
242
+ raise TypeError, "BNF for key #{key} is singular in class #{parent_class}; use #set to nil"
243
+ end
244
+ end
245
+
246
+ #
247
+ # Deletes the given key from the bnf_records hash.
248
+ #
249
+ def delete_key(key)
250
+ @bnf_records.delete(key)
251
+ end
252
+
253
+ #
254
+ # True if the record item is not nil (if the BnfItem is singular) or an
255
+ # empty array (if the BnfItem is multiple).
256
+ #
257
+ def has_data?(key)
258
+ bnf_item = bnf_spec[key]
259
+ if (bnf_item.multiple? and get(key).empty?) or
260
+ (not bnf_item.multiple? and get(key).nil?)
261
+ false
262
+ else
263
+ true
264
+ end
265
+ end
266
+
267
+ #
268
+ # Write the BNF records to file. Ensures that the required records exist
269
+ # according to the BnfSpec (otherwise an error is raised). A file object
270
+ # is expected.
271
+ #
272
+ def write(file, alt_bnf=nil)
273
+ # Loop through each BNF item
274
+ bnf = alt_bnf ? alt_bnf : bnf_spec
275
+ bnf.each_item do |bnf_item|
276
+ if has_data?(bnf_item.key)
277
+ if bnf_item.multiple?
278
+ get(bnf_item.key).each {|record| record.write(file)}
279
+ else
280
+ get(bnf_item.key).write(file)
281
+ end
282
+ elsif not bnf_item.optional?
283
+ raise "Required data in BNF are not set: #{bnf_item}"
284
+ end
285
+ end
286
+ end
287
+
288
+ ##########################################################################
289
+ # PRIVATE METHODS
290
+ ##########################################################################
291
+
292
+ private
293
+
294
+ #
295
+ # Used by #add and #set to convert a raw value into the proper class
296
+ # given the key (if needed). This method is not used outside of this
297
+ # class.
298
+ #
299
+ def coerce_record_value(key, value)
300
+ if value.kind_of?(Record) or value.kind_of?(Group)
301
+ value
302
+ else
303
+ Record.new(key, value)
304
+ end
305
+ end
306
+
307
+ end
308
+ end
309
+
@@ -0,0 +1,53 @@
1
+ require 'gdsii/element'
2
+ require 'gdsii/mixins'
3
+
4
+ module Gdsii
5
+
6
+ #
7
+ # Represents a GDSII Boundary element (i.e. a rectangle or polygon). Most
8
+ # methods are from Element or from the various included Access module
9
+ # methods.
10
+ #
11
+ class Boundary < Element
12
+
13
+ # Include various record accessors
14
+ include Access::Layer
15
+ include Access::Datatype
16
+ include Access::XY
17
+ include Access::ELFlags
18
+ include Access::Plex
19
+
20
+ #
21
+ # Boundary BNF description:
22
+ #
23
+ # <boundary> ::= BOUNDARY [ELFLAGS] [PLEX] LAYER DATATYPE XY
24
+ #
25
+ self.bnf_spec = BnfSpec.new(
26
+ BnfItem.new(GRT_BOUNDARY),
27
+ BnfItem.new(GRT_ELFLAGS, true),
28
+ BnfItem.new(GRT_PLEX, true),
29
+ BnfItem.new(GRT_LAYER),
30
+ BnfItem.new(GRT_DATATYPE),
31
+ BnfItem.new(GRT_XY),
32
+ BnfItem.new(Properties,true),
33
+ BnfItem.new(GRT_ENDEL)
34
+ )
35
+
36
+ #
37
+ # Boundary object constructor. Layer and datatype are given as Fixnum
38
+ # and the coordinate points are given as an array of Fixnum alternating
39
+ # x and y values (coordinate pair range is 4-200). Example:
40
+ #
41
+ # rectangle = Gdsii::Boundary.new(1, 0, [0,0, 0,10, 10,10, 10,0, 0,0])
42
+ #
43
+ def initialize(layer=nil, datatype=nil, xy=nil)
44
+ super()
45
+ @records[GRT_BOUNDARY] = Record.new(GRT_BOUNDARY)
46
+ self.layer = layer unless layer.nil?
47
+ self.datatype = datatype unless datatype.nil?
48
+ self.xy = xy unless xy.nil?
49
+ yield self if block_given?
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,65 @@
1
+ require 'gdsii/group'
2
+ require 'gdsii/element'
3
+
4
+ module Gdsii
5
+
6
+ #
7
+ # Represents a GDSII box element. Most methods are from Element or from the
8
+ # various included Access module methods.
9
+ #
10
+ class Box < Element
11
+
12
+ # Include various record accessors
13
+ include Access::Layer
14
+ include Access::XY
15
+ include Access::ELFlags
16
+ include Access::Plex
17
+
18
+ #
19
+ # Box BNF description:
20
+ #
21
+ # <box> ::= BOX [ELFLAGS] [PLEX] LAYER BOXTYPE XY
22
+ #
23
+ self.bnf_spec = BnfSpec.new(
24
+ BnfItem.new(GRT_BOX),
25
+ BnfItem.new(GRT_ELFLAGS, true),
26
+ BnfItem.new(GRT_PLEX, true),
27
+ BnfItem.new(GRT_LAYER),
28
+ BnfItem.new(GRT_BOXTYPE),
29
+ BnfItem.new(GRT_XY),
30
+ BnfItem.new(Properties, true),
31
+ BnfItem.new(GRT_ENDEL)
32
+ )
33
+
34
+ #
35
+ # Create a box record grouping given a layer, boxtype, and xy coordinates.
36
+ # The box object is to have exactly 5 coordinate pairs.
37
+ #
38
+ # box = Gdsii::Box.new(1, 0, [0,0, 0,10, 10,10, 10,0, 0,0])
39
+ #
40
+ def initialize(layer=nil, boxtype=nil, xy=nil)
41
+ super()
42
+ @records[GRT_BOX] = Record.new(GRT_BOX)
43
+ self.layer = layer unless layer.nil?
44
+ self.boxtype = boxtype unless boxtype.nil?
45
+ self.xy = xy unless xy.nil?
46
+ yield self if block_given?
47
+ end
48
+
49
+ #
50
+ # Get the boxtype record (returns Record).
51
+ #
52
+ def boxtype_record() @records.get(GRT_BOXTYPE); end
53
+
54
+ #
55
+ # Get the boxtype number (returns Fixnum).
56
+ #
57
+ def boxtype() @records.get_data(GRT_BOXTYPE); end
58
+
59
+ #
60
+ # Set the boxtype number.
61
+ #
62
+ def boxtype=(val) @records.set(GRT_BOXTYPE, val); end
63
+
64
+ end
65
+ end
@@ -0,0 +1,36 @@
1
+ #
2
+ # ByteOrder is lifted from ruby-talk 107439, cited by Michael Neumann
3
+ #
4
+ module ByteOrder
5
+
6
+ Native = :Native
7
+ Big = BigEndian = Network = :BigEndian
8
+ Little = LittleEndian = :LittleEndian
9
+
10
+ # examines the locale byte order on the running machine
11
+ def byte_order
12
+ if [0x12345678].pack("L") == "\x12\x34\x56\x78"
13
+ BigEndian
14
+ else
15
+ LittleEndian
16
+ end
17
+ end
18
+ alias byteorder byte_order
19
+ module_function :byte_order, :byteorder
20
+
21
+ def little_endian?
22
+ byte_order == LittleEndian
23
+ end
24
+
25
+ def big_endian?
26
+ byte_order == BigEndian
27
+ end
28
+
29
+ alias little? little_endian?
30
+ alias big? big_endian?
31
+ alias network? big_endian?
32
+
33
+ module_function :little_endian?, :little?
34
+ module_function :big_endian?, :big?, :network?
35
+
36
+ end