mu 5.7.9 → 5.7.10

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.
@@ -1,21 +0,0 @@
1
- # Copyright (C) 2008 Mu Dynamics, Inc
2
- #
3
- # This program is confidential and proprietary to Mu Dynamics, Inc and
4
- # may not be reproduced, published or disclosed to others without its
5
- # authorization.
6
-
7
- module LibXML
8
- module XML
9
- class Node
10
- # Get first element, optionally with name.
11
- def first_element name=nil
12
- each_element do |element|
13
- if not name or name == element.name
14
- return element
15
- end
16
- end
17
- return nil
18
- end
19
- end
20
- end
21
- end
@@ -1,559 +0,0 @@
1
- # Copyright (C) 2008 Mu Dynamics, Inc
2
- #
3
- # This program is confidential and proprietary to Mu Dynamics, Inc and
4
- # may not be reproduced, published or disclosed to others without its
5
- # authorization.
6
-
7
- require 'libxml'
8
- require 'mu/libxml'
9
-
10
- # Helper mixin for XML serialization.
11
- #
12
- # Example:
13
- # class MyObject
14
- # include XMLizable
15
- # xmlizable 'my-object' do
16
- # xml_element :a, Integer
17
- # xml_attribute :b, String, :required => true
18
- # end
19
- # ...
20
- module XMLizable
21
- class XMLParseError < StandardError ; end
22
-
23
- def self.included klass
24
- super
25
- klass.extend XMLizableClassMethods
26
- end
27
-
28
- module XMLizableClassMethods
29
- # Declare object to be XML serializable. If name is not given, the
30
- # object itself cannot be serialized and only XMLizable subclasses can.
31
- def xmlizable name=nil #block
32
- if defined? @xmlizable_called
33
- raise ArgumentError, "Only call xmlizable once"
34
- end
35
- @xmlizable_called = true
36
- @xmlizable_name = name
37
- @xmlizable_classes = {}
38
- if name
39
- # Add this class to ancestor's XMLizable class map.
40
- classes = ancestors.select { |ancestor| ancestor < XMLizable }
41
- classes.each do |ancestor|
42
- if ancestor.instance_variable_defined? :@xmlizable_classes
43
- classes =
44
- ancestor.instance_variable_get :@xmlizable_classes
45
- classes[name] = self
46
- end
47
- end
48
- end
49
-
50
- # Set xmlizable elements and attributes in block
51
- @xmlizable_elements = []
52
- @xmlizable_attributes = []
53
- if block_given?
54
- yield
55
- end
56
-
57
- # Re-init to merge in ancestor elements and attributes
58
- init_elements_and_attrs
59
- end
60
-
61
- # Initialize @xmlizable_elements and @xmlizable_attributes
62
- def init_elements_and_attrs
63
- # Get non-duplicate elements/attibutes from ancestors (including
64
- # current class)
65
- elems = []
66
- attrs = []
67
- attr_names = Set.new
68
- elem_names = Set.new
69
- ancestors.each do |klass|
70
- next unless klass < XMLizable
71
- if klass.instance_variable_defined? :@xmlizable_elements
72
- klass.xmlizable_elements.reverse_each do |e|
73
- elems.unshift e unless elem_names.include? e.name
74
- elem_names << e.name
75
- end
76
- end
77
- if klass.instance_variable_defined? :@xmlizable_attributes
78
- klass.xmlizable_attributes.reverse_each do |a|
79
- attrs.unshift a unless attr_names.include? a.name
80
- attr_names << a.name
81
- end
82
- end
83
- end
84
- @xmlizable_attributes = attrs.freeze
85
- @xmlizable_elements = elems.freeze
86
- end
87
-
88
- # There may be subclasses that indirectly include XMLizable or that never
89
- # call xmlizable. Use inherited hook to make sure they are initialized
90
- def inherited(klass)
91
- klass.init_elements_and_attrs
92
- end
93
-
94
- # Declare variable to be serialized as an XML element of type.
95
- def xml_element name, klass, *opts
96
- element = xml_object name, klass, *opts
97
- @xmlizable_elements << element
98
- end
99
-
100
- # Declare variable to be serialized as an array of XML element with
101
- # of type. The type must support to/from_libxml.
102
- def xml_elements name, klass, *opts
103
- element = xml_object name, klass, *opts
104
- element.array = true
105
- @xmlizable_elements << element
106
- end
107
-
108
- # Declare variable to be serialized as an XML attribute of type.
109
- def xml_attribute name, klass, *opts
110
- attribute = xml_object name, klass, *opts
111
- @xmlizable_attributes << attribute
112
- end
113
-
114
- def xmlizable_name
115
- @xmlizable_name
116
- end
117
-
118
- # Get list of elements.
119
- def xmlizable_elements
120
- @xmlizable_elements
121
- end
122
-
123
- # Get list of attributes.
124
- def xmlizable_attributes
125
- @xmlizable_attributes
126
- end
127
-
128
- # Create object to XML::Node. The object must be creatable by
129
- # calling a constructor with no arguments.
130
- def from_libxml node
131
- if node.name != @xmlizable_name
132
- xmlizable_classes = @xmlizable_classes
133
- klass = xmlizable_classes[node.name]
134
- if klass and klass != self
135
- return klass.from_libxml(node)
136
- else
137
- raise XMLParseError, "Unknown element: #{node.name}"
138
- end
139
- end
140
-
141
- object = self.new
142
- @xmlizable_attributes.each do |attribute|
143
- value = node[attribute.xml_name]
144
- if value
145
- attribute_klass = attribute.klass
146
- if attribute_klass == String
147
- # Common case with no special treatment
148
- elsif attribute_klass <= Integer
149
- value = value.to_i
150
- elsif attribute_klass <= Float
151
- value = value.to_f
152
- elsif attribute_klass <= TrueClass
153
- if value == 'true'
154
- value = true
155
- elsif value == 'false'
156
- value = false
157
- else
158
- raise XMLParseError, 'Invalid boolean value: ' +
159
- value.inspect
160
- end
161
- elsif attribute_klass <= Symbol
162
- begin
163
- value = value.to_sym
164
- rescue ArgumentError
165
- raise XMLParseError, "Invalid value: #{value.inspect} in #{node.name}"
166
- end
167
- if attribute.enum and not attribute.enum.member? value
168
- raise XMLParseError, "Invalid value: #{value.inspect} in #{node.name}"
169
- end
170
- end
171
- object.send :"#{attribute.name}=", value
172
- elsif attribute.required
173
- raise XMLParseError, "Required attribute missing: " +
174
- attribute.xml_name + ' in ' + node.name
175
- else
176
- object.send "#{attribute.name}=", attribute.default
177
- end
178
- end
179
- @xmlizable_elements.each do |element|
180
- element_node = node.first_element element.xml_name
181
- if element_node
182
- element_klass = element.klass
183
- if element_klass == String or element_klass == Mu::Scenario::Field::Reference
184
- content = element_node.content
185
- case element.escape
186
- when :default
187
- content.delete! TAB_CR_LF
188
- value = XMLizable.unescape content
189
- when :no_newline
190
- content.delete! TAB_CR
191
- value = XMLizable.unescape content
192
- when :regexp
193
- value = content
194
- else
195
- raise XMLParseError, "Unknown escape type: #{element.escape}"
196
- end
197
- elsif element_klass == Integer
198
- value = element_node.content.to_i(0)
199
- elsif element.array
200
- value = []
201
- element_node.each_element do |value_node|
202
- value << element.klass.from_libxml(value_node)
203
- end
204
- elsif element_klass == Float
205
- value = element_node.content.to_f
206
- elsif element_klass == Symbol
207
- value = element_node.content
208
- begin
209
- value = value.to_sym
210
- rescue ArgumentError
211
- raise XMLParseError, "Invalid value: #{value.inspect} in #{node.name}"
212
- end
213
- if element.enum and not element.enum.member? value
214
- raise XMLParseError, "Invalid value: #{value.inspect} in #{node.name}"
215
- end
216
- elsif element_klass == TrueClass
217
- value = element_node.content
218
- if value == 'true'
219
- value = true
220
- elsif value == 'false'
221
- value = false
222
- else
223
- raise XMLParseError, 'Invalid boolean value: ' +
224
- value.inspect
225
- end
226
- else
227
- value_node = element_node.first_element
228
- if not value_node
229
- raise XMLParseError, 'Element missing value: ' +
230
- element.xml_name + ' in ' + node.name
231
- end
232
- value = element_klass.from_libxml value_node
233
- end
234
- object.send :"#{element.name}=", value
235
- elsif element.required
236
- raise XMLParseError, 'Required element missing: ' +
237
- element.xml_name + ' in ' + node.name
238
- else
239
- object.send :"#{element.name}=", element.default
240
- end
241
- end
242
- object.post_from_libxml node
243
- return object
244
- end
245
-
246
- private
247
-
248
- # Create new XML serializable object. Internal helper method.
249
- XMLObject = ::Struct.new :name, :klass, :default, :required, :internal,
250
- :array, :enum, :xml_name, :label, :doc, :escape
251
- def xml_object name, klass, *opts
252
- # Get default value
253
- if not opts[0].is_a? Hash
254
- default = opts.shift
255
- else
256
- default = nil
257
- end
258
- array = false
259
- if opts[-1]
260
- required = opts[-1].fetch :required, false
261
- internal = opts[-1].fetch :internal, false
262
- enum = opts[-1][:enum]
263
- xml_name = opts[-1].fetch :xml_name, name.to_s
264
- label = opts[-1][:label]
265
- doc = opts[-1][:doc]
266
- escape = opts[-1].fetch :escape, :default
267
- else
268
- required = false
269
- internal = false
270
- enum = nil
271
- xml_name = name.to_s
272
- label = nil
273
- doc = nil
274
- escape = :default
275
- end
276
- return XMLObject.new(name, klass, default, required, internal,
277
- array, enum, xml_name, label, doc, escape)
278
- end
279
- end
280
-
281
- # Traverses the XMLizable tree rooted at the current node, passing
282
- # each child node to the associated block. If the block returns a
283
- # value other than nil or false the child is replaced with that
284
- # value.
285
- def xmlizable_replace_nodes &block
286
- self.class.xmlizable_attributes.each do |attribute|
287
- obj = self.send attribute.name
288
- if nobj = block.call(obj)
289
- self.send :"#{attribute.name}=", nobj
290
- end
291
- end
292
-
293
- self.class.xmlizable_elements.each do |element|
294
- obj = self.send element.name
295
- recurse = element.klass <= XMLizable
296
- if element.array
297
- obj.each_with_index do |sub_obj,i|
298
- if nsub_obj = block.call(sub_obj)
299
- obj[i] = nsub_obj
300
- elsif sub_obj and recurse
301
- sub_obj.xmlizable_replace_nodes(&block)
302
- end
303
- end
304
- else
305
- if nobj = block.call(obj)
306
- self.send :"#{element.name}=", nobj
307
- elsif obj and recurse
308
- obj.xmlizable_replace_nodes(&block)
309
- end
310
- end
311
- end
312
- end
313
-
314
- def xmlizable_map! &block
315
- self.class.xmlizable_attributes.each do |attribute|
316
- obj = self.send attribute.name
317
- if nobj = block.call(obj) and not nobj.equal?(obj)
318
- self.send :"#{attribute.name}=", nobj
319
- end
320
- end
321
-
322
- self.class.xmlizable_elements.each do |element|
323
- obj = self.send element.name
324
- if element.array
325
- obj.each_with_index do |sub_obj,i|
326
- if nsub_obj = block.call(sub_obj) and not nsub_obj.equal?(sub_obj)
327
- obj[i] = nsub_obj
328
- end
329
- end
330
- else
331
- if nobj = block.call(obj) and not nobj.equal?(obj)
332
- self.send :"#{element.name}=", nobj
333
- end
334
- end
335
- end
336
- end
337
-
338
- def xmlizable_each &block
339
- self.class.xmlizable_attributes.each do |attribute|
340
- obj = self.send attribute.name
341
- block.call(obj)
342
- end
343
-
344
- self.class.xmlizable_elements.each do |element|
345
- obj = self.send element.name
346
- if element.array
347
- obj.each do |sub_obj|
348
- block.call(sub_obj)
349
- end
350
- else
351
- block.call(obj)
352
- end
353
- end
354
- end
355
-
356
- # Recuses through xmlizable tree, yielding each element and attribute
357
- # to the supplied block. You can stop recursion at a given node
358
- # with "throw :prune" (like Find.find from stdlib)
359
- def xmlizable_find &block
360
- catch :prune do
361
- block.call(self)
362
-
363
- self.class.xmlizable_attributes.each do |attribute|
364
- catch :prune do
365
- obj = self.send attribute.name
366
- block.call(obj)
367
- end
368
- end
369
-
370
- self.class.xmlizable_elements.each do |element|
371
- obj = self.send element.name
372
- next if not obj
373
-
374
- recurse = element.klass <= XMLizable
375
- if element.array
376
- obj.each do |sub_obj|
377
- next unless sub_obj
378
- if recurse
379
- sub_obj.xmlizable_find(&block)
380
- end
381
- end
382
- else
383
- if recurse
384
- obj.xmlizable_find(&block)
385
- end
386
- end
387
- end
388
- end
389
- end
390
-
391
- # Same as xmlizable_find but only yields elements.
392
- def xmlizable_find_elements &block
393
- catch :prune do
394
- block.call(self)
395
-
396
- self.class.xmlizable_elements.each do |element|
397
- obj = self.send element.name
398
- next if not obj
399
-
400
- recurse = element.klass <= XMLizable
401
- if element.array
402
- obj.each do |sub_obj|
403
- next unless sub_obj
404
- if recurse
405
- sub_obj.xmlizable_find_elements(&block)
406
- end
407
- end
408
- else
409
- if recurse
410
- obj.xmlizable_find_elements(&block)
411
- end
412
- end
413
- end
414
- end
415
- end
416
-
417
- # Convert object to XML::Node
418
- def xmlizable_to_libxml
419
- name = self.class.instance_variable_get :@xmlizable_name
420
- if not name
421
- raise ArgumentError, 'Cannot convert nameless class to XML: ' +
422
- self.class.name
423
- end
424
- node = LibXML::XML::Node.new name
425
- self.class.xmlizable_attributes.each do |attribute|
426
- value = self.send attribute.name
427
- if value == attribute.default and not attribute.required
428
- next
429
- end
430
- node[attribute.xml_name] = value.to_s
431
- end
432
- self.class.xmlizable_elements.each do |element|
433
- value = self.send element.name
434
- element_klass = element.klass
435
- if value == element.default and not element.required
436
- next
437
- end
438
- element_node = LibXML::XML::Node.new element.xml_name
439
- node << element_node
440
- if element.array
441
- value.each do |sub_value|
442
- element_node << sub_value.to_libxml
443
- end
444
- elsif element_klass <= Integer or element_klass <= Float
445
- element_node.content = value.to_s
446
- elsif element_klass <= Symbol or element_klass <= TrueClass
447
- element_node.content = value.to_s
448
- elsif element_klass <= String
449
- value = value.to_s.dup
450
- case element.escape
451
- when :default
452
- element_node << XMLizable.escape(value, ESCAPES)
453
- when :no_newline
454
- element_node << XMLizable.escape(value, ESCAPES_NO_NEWLINE)
455
- when :regexp
456
- element_node << XMLizable.escape(value, ESCAPES_RE)
457
- else
458
- raise ArgumentError, "Unknown escape type: #{escape_table}"
459
- end
460
- else
461
- element_node << value.to_libxml
462
- end
463
- end
464
- return node
465
- end
466
-
467
- alias :to_libxml :xmlizable_to_libxml
468
-
469
- # Hook for logic after de-serializing an object.
470
- def post_from_libxml node
471
- end
472
-
473
-
474
- # Default map used for unescaping.
475
- # Backslash escapes are not substituted unless they are defined here
476
- # (or in a map explicitly passed to XMLizable.unescape). The exception
477
- # to this is "\x" sequences like "\x0a" which are always substituted.
478
- UNESCAPE_MAP = {
479
- 'n' => "\n",
480
- 't' => "\t",
481
- 'r' => "\r",
482
- '\\' => "\\"
483
- }
484
-
485
- # 1 2 3
486
- RE_ESCAPE = /\A([^\\]+)?(?:\\(?:(?:x([0-9a-fA-F]{1,2}))|(.)))?/
487
- # 1: optional text in front with no escapes
488
- # then we parse optional escape sequence:
489
- # 2: hex from \x escape
490
- # 3: char from other escapes
491
-
492
- # Returns an unescaped copy of string s.
493
- def self.unescape s, unescape_map=nil
494
- unescape_map ||= UNESCAPE_MAP
495
-
496
- input = s.dup
497
- output = []
498
- until input.empty?
499
- input.slice! RE_ESCAPE
500
- # leading text with no escape sequences
501
- output << $1 if $1
502
- if $2
503
- # We have an \x escape code. Interpret hex and get character.
504
- output << $2.hex.chr
505
- elsif $3
506
- # We have something like \t. Interpet it if we can, otherwise preserve both characters
507
- output << unescape_map.fetch($3,"\\#$3")
508
- end
509
- end
510
- output.join
511
- end
512
-
513
- # Default table used for converting ascii code to escaped representation
514
- ESCAPES = Array.new 256 do |i|
515
- case i
516
- when 9; "\\t".freeze
517
- when 13; "\\r".freeze
518
- when 92; "\\\\".freeze
519
- when 10; "\\n".freeze
520
- when 32..126; i.chr.freeze
521
- else ; ('\x%02x' % i).freeze
522
- end
523
- end
524
- ESCAPES.freeze
525
- # Text escaped with ESCAPES should not have any of these characters in it.
526
- TAB_CR_LF = "\t\r\n".freeze
527
-
528
- ESCAPES_NONE = Array.new(256) { |i| i.chr.freeze }
529
- ESCAPES_NONE.freeze
530
-
531
- # Regular expressions are escaped when writing to xml but not when
532
- # reading from XML. This is necessary because XML doesn't allow
533
- # some (all?) binary characters. Escaping doesn't change the meaning
534
- # of the regex and does not need to be reversed when deserealizing.
535
- ESCAPES_RE = Array.new 256 do |i|
536
- case i
537
- when 32..126; i.chr.freeze
538
- else ; ('\x%02x' % i).freeze
539
- end
540
- end
541
- ESCAPES_RE.freeze
542
-
543
- # Alternate escape table that doesn't escape newline characters
544
- ESCAPES_NO_NEWLINE = ESCAPES.dup
545
- ESCAPES_NO_NEWLINE[10] = "\n".freeze
546
- ESCAPES_NO_NEWLINE.freeze
547
- # Text escaped with ESCAPES_NO_NEWLINE should not have any of these characters in it.
548
- TAB_CR = "\t\r".freeze
549
-
550
- # Takes input and a table that maps ascii codes to their representation
551
- def self.escape input, escapes=nil
552
- escapes ||= ESCAPES
553
- output = []
554
- input.each_byte do |i|
555
- output << escapes[i]
556
- end
557
- output.join
558
- end
559
- end