udat 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.
Files changed (3) hide show
  1. data/LICENSE +23 -0
  2. data/lib/udat.rb +803 -0
  3. metadata +51 -0
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ # Copyright (c) 2007 FlexiGuided GmbH, Berlin
2
+ #
3
+ # Author: Jan Behrens
4
+ #
5
+ # Website: http://www.flexiguided.de/publications.flexirecord.en.html
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in
15
+ # all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ # SOFTWARE.
@@ -0,0 +1,803 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'monitor'
4
+
5
+
6
+ # Copyright (c) 2007 FlexiGuided GmbH, Berlin
7
+ #
8
+ # Author: Jan Behrens
9
+ #
10
+ # Website: http://www.flexiguided.de/publications.udat.en.html
11
+ #
12
+ # -----
13
+ #
14
+ # Abstract class of an UDAT object. UDAT objects basically consist of a tag
15
+ # and the content. The tag can be a String or be nil. The content is either
16
+ # a scalar value stored as a String, or an ordered/unordered collection of
17
+ # values (where each value can optionally have a key associated with it).
18
+ # Keys and values of collections are always UDAT objects too.
19
+ #
20
+ # UDAT objects can most easily constructed from other ruby objects by using
21
+ # the Object#to_udat method.
22
+ #
23
+ # By calling the method Udat#encode, the UDAT object is encoded in a both
24
+ # easily human readable and easily machine readable format. The output can
25
+ # be later parsed by String#parse_udat.
26
+ class Udat
27
+
28
+ include MonitorMixin
29
+
30
+ # A string containing an UDAT example document.
31
+ ExampleDocument = <<-'END_OF_EXAMPLE'
32
+ This file contains several UDAT objects (each of them enclosed by
33
+ square brackets), serving as an example for the UDAT format:
34
+
35
+
36
+ Scalar values:
37
+
38
+ [Hello World!]
39
+
40
+ [UTF-8|Hello World!] This object has a tag "UTF-8".
41
+ Intepretation of tags is task of the
42
+ application, there are no standard tags
43
+ defined.
44
+
45
+ [23]
46
+
47
+ [integer|23]
48
+
49
+ [rational|2/3]
50
+
51
+
52
+ Arrays (or sets):
53
+
54
+ [ [1] [2] [3] ]
55
+
56
+ [ [1] [2] Comments are allowed here! (and alomost everywhere) [3] ]
57
+
58
+ [ [person| <firstname>[Max] <lastname>[Mustermann] ]
59
+ [person| <firstname>[Martin] <lastname>[html|M&uuml;ller] ]
60
+ [group| <name>[Sample group] <members> [
61
+ [person| <firstname>[Max] <lastname>[Mustermann] ]
62
+ [person| <firstname>[Martin] <lastname>[html|M&uuml;ller] ]
63
+ ] ] ]
64
+
65
+ References like in YAML with &id and *id
66
+ are not directly supported by UDAT.
67
+
68
+
69
+ Ordered or unordered maps:
70
+
71
+ [ <&> [html|&amp;]
72
+ <"> [html|&quot;]
73
+ <\<> [html|&lt;]
74
+ <\>> [html|&gt;] ]
75
+
76
+ [ <color combination|[red][blue]> [nice]
77
+ <color combination|[red][magenta]> [ugly] ]
78
+
79
+ [ < <red>[on] <yellow>[off] <green>[off] > [stop]
80
+ < <red>[on] <yellow>[on] <green>[off] > [attention]
81
+ < <red>[off] <yellow>[off] <green>[on] > [go]
82
+ < <red>[off] <yellow>[on] <green>[off] > [prepare to stop] ]
83
+
84
+
85
+ Sample configuration file:
86
+
87
+ [sample config v1.0|
88
+ <locale> [
89
+ <language> [de]
90
+ <timezone> [CET]
91
+ ]
92
+ <logging> [
93
+ <verbosity> [high]
94
+ <destination> [file|/var/log/sample.log]
95
+ ]
96
+ <network> [
97
+ <max connections> [256]
98
+ <reverse lookups> [yes]
99
+ ]
100
+ <access control> [
101
+ <allowed> [ [user|martin] [user|max] [group|admins] ]
102
+ ]
103
+ ]
104
+
105
+
106
+ END_OF_EXAMPLE
107
+
108
+ # Error raised by UdatCollection#fetch,
109
+ # when a fetched value doesn't have the expected tag (i.e. type).
110
+ class UdatTagMismatch < StandardError; end
111
+ # Error raised by UdatCollection#fetch,
112
+ # when a fetched value is a collection instead of a scalar or vice versa.
113
+ class UdatTypeMismatch < StandardError; end
114
+ # UDAT parsing error
115
+ class UdatParseError < StandardError; end
116
+
117
+ private_class_method :new
118
+ # Creates a new Udat object with a given tag (which may be nil).
119
+ # This method is private,
120
+ # Udat#initialize is only called through supercalls.
121
+ def initialize(tag)
122
+ super()
123
+ self.tag = tag
124
+ end
125
+
126
+ # Returns an escaped version of a string, where backslashes are preceding
127
+ # certain reserved characters.
128
+ def escape_string(string)
129
+ string.to_s.gsub /([<>\[\]|\\])/, "\\\\\\1"
130
+ end
131
+ private :escape_string
132
+
133
+ # Tag (i.e. type of the content).
134
+ attr_reader :tag
135
+ # Sets the tag (i.e. type of the content).
136
+ def tag=(tag)
137
+ synchronize do
138
+ @tag = tag ? tag.to_s : nil
139
+ end
140
+ return tag
141
+ end
142
+
143
+ # Returns true, if the UDAT object represents a scalar value.
144
+ def scalar?
145
+ kind_of? UdatScalar
146
+ end
147
+ # Returns true, if the UDAT object represents a collection.
148
+ def collection?
149
+ kind_of? UdatCollection
150
+ end
151
+
152
+ # Returns the data (including it's tag) encoded in the UDAT format.
153
+ #
154
+ # Note: The UDAT format doesn't contain information, whether contained
155
+ # collections are ordered or unordered. This information is lost during
156
+ # the encoding process, and has to be restored in an application
157
+ # specific way, if neccessary.
158
+ def encode
159
+ synchronize do
160
+ if tag
161
+ return "#{escape_string tag}|#{encoded_content}"
162
+ else
163
+ return encoded_content
164
+ end
165
+ end
166
+ end
167
+ # Here the method does the same as Udat#encode, but this method is
168
+ # overwritten in UdatScalar!
169
+ def to_s
170
+ encode
171
+ end
172
+ # Does the same as Udat#encode, but encloses the results in curly
173
+ # brackets and preceds them with the string "udat".
174
+ def inspect
175
+ "udat{#{self.encode}}"
176
+ end
177
+
178
+ # Returns a hash key used by ruby's Hash'es.
179
+ def hash
180
+ to_s.hash
181
+ end
182
+ # Returns true, if class, tag and content are matching another object.
183
+ def eql?(other)
184
+ self.class == other.class and
185
+ self.tag == other.tag and
186
+ self.to_s == other.to_s
187
+ end
188
+ # Same as Udat#eql?.
189
+ def ==(other)
190
+ self.eql? other
191
+ end
192
+
193
+ # Casts a value to an Udat object. If two arguments are supplied,
194
+ # the first argument is a tag, while the second is the content.
195
+ # If just one argument is supplied, then the tag is assumed to be nil,
196
+ # and the argument given is the content.
197
+ # Interpretation of the content depends on the type: If the content is
198
+ # an Array (responds to 'to_ary') an ordered collection will be created,
199
+ # if the content is a Hash (responds to 'to_hash'), an unordered
200
+ # collection will be created. Otherwise the content will be casted to a
201
+ # String with 'to_s' to be stored as a scalar.
202
+ # If you pass an Array, each element of that array may be an Array
203
+ # of size 2, in which case the 2 entries are used as key and value.
204
+ # If an element of the Array is not an Array, it will be used as value
205
+ # without an associated key.
206
+ # This method is called by Object#to_udat.
207
+ def self.construct(*args)
208
+ if args.length == 1
209
+ tag = nil
210
+ content = args[0]
211
+ elsif args.length == 2
212
+ tag = args[0]
213
+ content = args[1]
214
+ else
215
+ raise ArgumentError, "Wrong number of arguments supplied."
216
+ end
217
+ if content.kind_of? Udat
218
+ if tag
219
+ content = content.dup
220
+ content.tag = tag
221
+ end
222
+ return content
223
+ elsif content.respond_to? :to_ary
224
+ return UdatCollection.new(tag, content.to_ary)
225
+ elsif content.respond_to? :to_hash
226
+ return UdatCollection.new(tag, content.to_hash.to_a).unordered!
227
+ else
228
+ return UdatScalar.new(tag, content)
229
+ end
230
+ end
231
+
232
+ # Internal parsing function.
233
+ def self.parse_intern(input, start_pos = 0)
234
+ string = ""
235
+ tag = nil
236
+ key = nil
237
+ collection = nil
238
+ pos = start_pos
239
+ while pos < input.length
240
+ char = input[pos, 1]
241
+ case char
242
+ when "\\"
243
+ pos += 1
244
+ char = input[pos, 1]
245
+ if char.empty?
246
+ raise UdatParseError, "Backslash at end of input."
247
+ end
248
+ if char =~ /([<>\[\]|\\])/
249
+ string << char
250
+ elsif char == "\n"
251
+ elsif char == "\r"
252
+ next_char = input[pos + 1, 1]
253
+ pos += 1 if next_char == "\n"
254
+ else
255
+ raise UdatParseError, "Unknown escape sequence found."
256
+ end
257
+ pos += 1
258
+ when "|"
259
+ if tag
260
+ raise UdatParseError, "Multiple occurrences of pipe symbol."
261
+ end
262
+ tag = string
263
+ string = ""
264
+ pos += 1
265
+ when "<"
266
+ if key
267
+ raise UdatParseError, "Unexpected opening angle bracket."
268
+ end
269
+ key, pos = parse_intern(input, pos + 1)
270
+ unless input[pos, 1] == ">"
271
+ raise ArgumentError, "Closing angle bracket not found."
272
+ end
273
+ pos += 1
274
+ when ">"
275
+ break
276
+ when "["
277
+ value, pos = parse_intern(input, pos + 1)
278
+ unless input[pos, 1] == "]"
279
+ raise UdatParseError, "Closing square bracket not found."
280
+ end
281
+ collection ||= UdatCollection.new(tag, [])
282
+ if key
283
+ collection.append_pair(key, value)
284
+ key = nil
285
+ else
286
+ collection.append_value(value)
287
+ end
288
+ pos += 1
289
+ when "]"
290
+ break
291
+ else
292
+ string << char
293
+ pos += 1
294
+ end
295
+ end
296
+ raise UdatParseError, "Key without value." if key
297
+ return (collection ? collection : string.to_udat(tag)), pos
298
+ end
299
+ private_class_method :parse_intern
300
+
301
+ # Parses a given string and returns a structure of Udat objects.
302
+ #
303
+ # Note: When parsing UDAT data, no information is gained, whether
304
+ # collections are ordered or unordered. After parsing all collections
305
+ # will be marked as unordered, until changed.
306
+ def self.parse(input)
307
+ input = input.to_s
308
+ result, pos = parse_intern(input)
309
+ if pos < input.length
310
+ raise UdatParseError, "Closing bracket without opening bracket."
311
+ end
312
+ return result
313
+ end
314
+
315
+ end
316
+
317
+
318
+ # Class of UDAT objects holding an ordered or unordered collection of
319
+ # values (where each value can optionally have a key associated with it).
320
+ # Keys and values of collections are always UDAT objects too.
321
+ # UdatCollection's can be interpreted as maps, arrays, sets or any other
322
+ # non-scalar data structure.
323
+ #
324
+ # Note: Keys and values are always implicitly casted by all instance
325
+ # methods of this class to Udat objects using Object#to_udat.
326
+ class UdatCollection < Udat
327
+
328
+ public_class_method :new
329
+ # Creates a new Udat object with a given tag (which may be nil) and a
330
+ # given content, represented by a nested Array structure. See the source
331
+ # code for details. It is not recommended to use this method. Use
332
+ # Object#to_udat instead.
333
+ def initialize(tag, content)
334
+ super tag
335
+ @ordered = true
336
+ clear
337
+ unless content.nil?
338
+ if content.respond_to? :to_ary
339
+ content = content.to_ary
340
+ else
341
+ content = [content]
342
+ end
343
+ content.each { |entry| self << entry }
344
+ end
345
+ end
346
+
347
+ # Deletes the internal index hashes.
348
+ def index_void!
349
+ synchronize do
350
+ @key_to_value = nil
351
+ @value_to_key = nil
352
+ end
353
+ return self
354
+ end
355
+ # Checks, if the internal index hashes are existent
356
+ # (and therefore up to date).
357
+ def index_void?
358
+ synchronize do
359
+ return @key_to_value.nil?
360
+ end
361
+ end
362
+ # Creates index hashes, if they are not existent.
363
+ def require_index
364
+ synchronize do
365
+ if index_void?
366
+ @key_to_value = {}
367
+ @value_to_key = {}
368
+ @entries.each do |key, value|
369
+ unless key.nil?
370
+ @key_to_value[key] = value unless @key_to_value.has_key? key
371
+ @value_to_key[value] = key unless @value_to_key.has_key? value
372
+ end
373
+ end
374
+ end
375
+ end
376
+ return self
377
+ end
378
+ private :index_void!, :index_void?, :require_index
379
+
380
+ # Empties the collection.
381
+ def clear
382
+ @entries = []
383
+ @key_to_value = {}
384
+ @value_to_key = {}
385
+ return self
386
+ end
387
+ # Deletes all entries with a given key.
388
+ def delete_key(key)
389
+ key = key.to_udat
390
+ synchronize do
391
+ @entries.delete_if { |e_key, e_value| e_key == key }
392
+ index_void!
393
+ end
394
+ return self
395
+ end
396
+ # Deletes all entries with a given value.
397
+ def delete_value(value)
398
+ value = value.to_udat
399
+ synchronize do
400
+ @entries.delete_if { |e_key, e_value| e_value == value }
401
+ index_void!
402
+ end
403
+ return self
404
+ end
405
+
406
+ # Appends a new key with a new value.
407
+ def append_pair(key, value)
408
+ key = key.to_udat
409
+ value = value.to_udat
410
+ synchronize do
411
+ @entries << [key, value]
412
+ unless index_void?
413
+ @key_to_value[key] = value unless @key_to_value.has_key? key
414
+ @value_to_key[value] = key unless @value_to_key.has_key? value
415
+ end
416
+ end
417
+ return self
418
+ end
419
+ # Appends a new value.
420
+ def append_value(value)
421
+ value = value.to_udat
422
+ synchronize do
423
+ @entries << [nil, value]
424
+ end
425
+ return self
426
+ end
427
+ # Deletes all key/value pairs where the given key matches,
428
+ # and appends a new key/value pair.
429
+ def set_value_for_key(key, value)
430
+ delete_key(key)
431
+ append_pair(key, value)
432
+ return self
433
+ end
434
+ # Deletes all values or key/value pairs where the given value matches,
435
+ # and appends a new key/value pair.
436
+ def set_key_for_value(key, value)
437
+ delete_value(value)
438
+ append_pair(key, value)
439
+ return self
440
+ end
441
+
442
+ # Behaves differently depending on the type of the argument. If the
443
+ # argument is an Array (responds to 'to_ary') with 2 elements, a new
444
+ # key/value pair is added, with the key being the first element of the
445
+ # array, and the value being the second argument of the array. Arrays
446
+ # with any other number of elements cause an error. If the argument is
447
+ # not an array, then it is added as a value without a key.
448
+ def <<(value)
449
+ if value.respond_to? :to_ary
450
+ value = value.to_ary
451
+ unless value.length == 2
452
+ raise ArgumentError,
453
+ "#{value.length} array elements found, while 2 were expected."
454
+ end
455
+ return append_pair(value[0], value[1])
456
+ else
457
+ return append_value(value)
458
+ end
459
+ end
460
+ # Same as UdatCollection#set_value_for_key.
461
+ def []=(key, value)
462
+ set_value_for_key(key, value)
463
+ end
464
+
465
+ # Returns the key at a numeric index, or nil, if the index is out of
466
+ # bounds or at the given index there is only a value without key.
467
+ def key_by_index(index)
468
+ index = index.to_int
469
+ synchronize do
470
+ entry = @entries[index]
471
+ return entry ? entry[0] : nil
472
+ end
473
+ end
474
+ # Returns the value at a numeric index, or nil, if the index is out of
475
+ # bounds.
476
+ def value_by_index(index)
477
+ index = index.to_int
478
+ synchronize do
479
+ entry = @entries[index]
480
+ return entry ? entry[1] : nil
481
+ end
482
+ end
483
+ # Returns the first value having a given key.
484
+ def value_by_key(key)
485
+ synchronize do
486
+ require_index
487
+ return @key_to_value[key.to_udat]
488
+ end
489
+ end
490
+ # Returns the first key having a given value.
491
+ def key_by_value(value)
492
+ synchronize do
493
+ require_index
494
+ @value_to_key[value.to_udat]
495
+ end
496
+ end
497
+
498
+ # Behaves differently depending on the type of the argument.
499
+ # If the argument is an Integer the method behaves same as
500
+ # UdatCollection#value_by_index.
501
+ # Otherwise the method behaves same as UdatCollection#value_by_key.
502
+ def [](key)
503
+ if key.kind_of? Integer
504
+ return value_by_index(key)
505
+ else
506
+ return value_by_key(key)
507
+ end
508
+ end
509
+ # Same as UdatCollection#[], but raises an error, if no value was found.
510
+ # If an additional second argument is passed, an error will also be
511
+ # raised if the tag (i.e. type) of the value is not equal to the second
512
+ # argument.
513
+ def fetch(*args)
514
+ if args.length == 1
515
+ value = self[args[0]]
516
+ unless value
517
+ raise IndexError, "Value for the given key or index not found."
518
+ end
519
+ return value
520
+ elsif args.length == 2
521
+ value = fetch(args[0])
522
+ unless value.tag == args[1]
523
+ raise UdatTagMismatch, "UDAT tag mismatch."
524
+ end
525
+ return value
526
+ else
527
+ raise ArgumentError, "Wrong number of arguments supplied."
528
+ end
529
+ end
530
+ # Same as UdatCollection#fetch, but raises an error, if the value is
531
+ # not an UdatCollection.
532
+ def fetch_collection(*args)
533
+ value = fetch(*args)
534
+ if value.scalar?
535
+ raise UdatTypeMismatch,
536
+ "Scalar value found, where a collection was expected."
537
+ end
538
+ return value
539
+ end
540
+ # Same as UdatCollection#fetch, but raises an error, if the value is
541
+ # not an UdatScalar.
542
+ def fetch_scalar(*args)
543
+ value = fetch(*args)
544
+ if value.collection?
545
+ raise UdatTypeMismatch,
546
+ "Collection found, where a scalar value was expected."
547
+ end
548
+ return value
549
+ end
550
+ # Returns the first value of the collection, or nil if empty.
551
+ def first
552
+ self[0]
553
+ end
554
+ # Returns the last value of the collection, or nil if empty.
555
+ def last
556
+ self[-1]
557
+ end
558
+
559
+ # Returns the number of values in the collection.
560
+ def length
561
+ synchronize do
562
+ @entries.length
563
+ end
564
+ end
565
+ alias size length
566
+ # Returns true, if the collection is empty.
567
+ def empty?
568
+ length == 0
569
+ end
570
+ # Calls a given block for each numeric index.
571
+ def each_index
572
+ synchronize do
573
+ (0...length).each { |i| yield i }
574
+ end
575
+ return self
576
+ end
577
+
578
+ # Returns an Array containing the key/value pairs each as an Array of
579
+ # size 2. If there is no key, the first element of the sub Array is nil.
580
+ def key_value_pairs
581
+ synchronize do
582
+ return @entries.collect { |entry| entry.dup }
583
+ end
584
+ end
585
+ # Returns an Array containing all keys of the collection.
586
+ def keys
587
+ keys = nil
588
+ synchronize do
589
+ keys = @entries.collect { |key, value| key }
590
+ end
591
+ keys.compact!
592
+ return keys
593
+ end
594
+ # Returns an Array containing all values of the collection.
595
+ def values
596
+ synchronize do
597
+ return @entries.collect { |key, value| value }
598
+ end
599
+ end
600
+
601
+ # Returns a hash, where each key is mapped to the respective value.
602
+ def to_hash
603
+ hash = {}
604
+ synchronize do
605
+ @entries.each do |key, value|
606
+ next if key.nil?
607
+ hash[key] = value unless hash.has_key? key
608
+ end
609
+ end
610
+ return hash
611
+ end
612
+ # Same as UdatCollection#values.
613
+ def to_ary
614
+ values
615
+ end
616
+ alias to_a values
617
+
618
+ # Appends the values (and corresponding keys) of another UdatCollection.
619
+ def concat(other)
620
+ synchronize do
621
+ other.key_value_pairs.each do |key, value|
622
+ if key.nil?
623
+ append_value(value)
624
+ else
625
+ append_pair(key, value)
626
+ end
627
+ end
628
+ end
629
+ return self
630
+ end
631
+ # Replaces the values (and corresponding keys) with the values/keys of
632
+ # another UdatCollection.
633
+ def replace(other)
634
+ synchronize do
635
+ clear
636
+ concat(other)
637
+ end
638
+ return self
639
+ end
640
+
641
+ # Returns the encoded form of the content as a string.
642
+ # This method is used by Udat#encode, which returns the complete encoding
643
+ # of the data (including the tag).
644
+ def encoded_content
645
+ synchronize do
646
+ return (
647
+ @entries.collect do |key, value|
648
+ if key
649
+ "<#{key.encode}>[#{value.encode}]"
650
+ else
651
+ "[#{value.encode}]"
652
+ end
653
+ end.join
654
+ )
655
+ end
656
+ end
657
+
658
+ # Same as UdatCollection#ordered?.
659
+ def ordered
660
+ synchronize do
661
+ return @ordered
662
+ end
663
+ end
664
+ # Returns false, if the order of the contents of this collection is to be
665
+ # ignored for comparisons.
666
+ def ordered?
667
+ self.ordered
668
+ end
669
+ # Returns true, if the order of the contents of this collection is to be
670
+ # ignored for comparisons.
671
+ def unordered?
672
+ not self.ordered
673
+ end
674
+ # If set to false, the order of the contents of this collection will be
675
+ # ignored for comparisons.
676
+ def ordered=(ordered)
677
+ synchronize do
678
+ index_void!
679
+ if ordered == false
680
+ @ordered = false
681
+ else
682
+ @ordered = true
683
+ end
684
+ end
685
+ end
686
+ # Same as UdatCollection#ordered = false, but returns self.
687
+ def unordered!
688
+ self.ordered = false
689
+ return self
690
+ end
691
+ # Same as UdatCollection#ordered = true, but returns self.
692
+ def ordered!
693
+ self.ordered = true
694
+ return self
695
+ end
696
+
697
+ # Same as Udat#inspect, but in case of unordered collections it prepends
698
+ # "udat-unordered" instead of just "udat".
699
+ def inspect
700
+ if ordered?
701
+ return super
702
+ else
703
+ "udat-unordered{#{self.encode}}"
704
+ end
705
+ end
706
+
707
+ # Returns a hash key used by ruby's Hash'es.
708
+ def hash
709
+ hash = 0
710
+ @entries.each do |key, value|
711
+ hash += key.hash
712
+ hash += value.hash
713
+ end
714
+ return hash
715
+ end
716
+ # Returns true, if class, tag and content are matching another object.
717
+ # The order of the content is ignored, if this or the other object has
718
+ # the 'ordered' attribute set to false.
719
+ def eql?(other)
720
+ if self.class == other.class and self.tag == other.tag
721
+ if self.ordered? and other.ordered?
722
+ return self.to_s == other.to_s
723
+ else
724
+ own_pairs = self.key_value_pairs
725
+ other_pairs = other.key_value_pairs
726
+ own_pairs.each do |own_pair|
727
+ catch :found do
728
+ other_pairs.each_index do |index|
729
+ if own_pair.eql? other_pairs[index]
730
+ other_pairs.delete_at index
731
+ throw :found
732
+ end
733
+ end
734
+ return false
735
+ end
736
+ end
737
+ return true
738
+ end
739
+ else
740
+ return false
741
+ end
742
+ end
743
+
744
+ end
745
+
746
+
747
+ # Class of UDAT objects holding scalar values (stored as a String).
748
+ class UdatScalar < Udat
749
+
750
+ public_class_method :new
751
+ # Creates a new Udat object with a given tag (which may be nil) and a
752
+ # given content, which is transformed to a string (via 'to_s').
753
+ # It is not recommended to use this method. Use Object#to_udat instead.
754
+ def initialize(tag, content)
755
+ super tag
756
+ self.content = content
757
+ end
758
+
759
+ # Content of the scalar (a String).
760
+ attr_reader :content
761
+ def content=(content)
762
+ @content = content.to_s
763
+ end
764
+
765
+ # Same as UdatScalar#content.
766
+ def to_s
767
+ content
768
+ end
769
+ # Returns the content casted to an Integer.
770
+ def to_i
771
+ content.to_i
772
+ end
773
+
774
+ # Returns true, if the (String representation of the) content is empty.
775
+ def empty?
776
+ self.to_s.empty?
777
+ end
778
+
779
+ # Returns the encoded form of the content as a string.
780
+ # In this case this is simply an escaped version of the String.
781
+ # This method is used by Udat#encode, which returns the complete encoding
782
+ # of the data (including the tag).
783
+ def encoded_content
784
+ escape_string(self.to_s)
785
+ end
786
+
787
+ end
788
+
789
+
790
+ class Object
791
+ # Calls Udat.construct(tag, self).
792
+ def to_udat(tag = nil)
793
+ Udat.construct(tag, self)
794
+ end
795
+ end
796
+
797
+ class String
798
+ # Calls Udat.parse(self).
799
+ def parse_udat
800
+ Udat.parse(self)
801
+ end
802
+ end
803
+
metadata ADDED
@@ -0,0 +1,51 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.0
3
+ specification_version: 1
4
+ name: udat
5
+ version: !ruby/object:Gem::Version
6
+ version: 1.0.0
7
+ date: 2007-05-22 00:00:00 +00:00
8
+ summary: Parser and generator for UDAT documents, a generic data format similar to XML or YAML.
9
+ require_paths:
10
+ - lib/
11
+ email: jan.behrens@flexiguided.de
12
+ homepage: http://www.flexiguided.de/publications.udat.en.html
13
+ rubyforge_project:
14
+ description:
15
+ autorequire: udat
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Jan Behrens
31
+ files:
32
+ - ./LICENSE
33
+ - lib/udat.rb
34
+ test_files: []
35
+
36
+ rdoc_options:
37
+ - --title
38
+ - UDAT Documentation
39
+ - --main
40
+ - Udat
41
+ - --line-numbers
42
+ extra_rdoc_files: []
43
+
44
+ executables: []
45
+
46
+ extensions: []
47
+
48
+ requirements: []
49
+
50
+ dependencies: []
51
+