udat 1.1.0 → 1.1.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.
Files changed (2) hide show
  1. data/lib/udat.rb +111 -56
  2. metadata +1 -1
data/lib/udat.rb CHANGED
@@ -17,19 +17,23 @@ require 'monitor'
17
17
  # values (where each value can optionally have a key associated with it).
18
18
  # Keys and values of collections are always UDAT objects too.
19
19
  #
20
- # UDAT objects can most easily constructed from other ruby objects by using
21
- # the Object#to_udat method.
20
+ # UDAT objects can most easily be constructed from other ruby objects by
21
+ # using the Object#to_udat method.
22
22
  #
23
23
  # By calling the method Udat#encode, the UDAT object is encoded in a both
24
24
  # easily human readable and easily machine readable format. The output can
25
- # be later parsed by String#parse_udat.
25
+ # be later parsed by String#parse_udat, or if it is enclosed in square
26
+ # brackets by IO#read_udat.
26
27
  class Udat
27
28
 
28
29
  include MonitorMixin
29
30
 
31
+ # Special argument passed to Udat#to_udat, if the tag is to be kept.
32
+ KeepTag = Object.new
33
+
30
34
  # A string containing an UDAT example document.
31
35
  ExampleDocument = <<-'END_OF_EXAMPLE'
32
- This file contains several UDAT objects (each of them enclosed by
36
+ This file contains several UDAT objects (each of them enclosed in
33
37
  square brackets), serving as an example for the UDAT format:
34
38
 
35
39
 
@@ -103,6 +107,21 @@ class Udat
103
107
  ]
104
108
 
105
109
 
110
+ Don't abuse tags to store complicated meta information like this:
111
+
112
+ WRONG! [string charset=ISO-8859-1 language=EN|Hello World!] WRONG!
113
+
114
+
115
+ If you need to store more complicated meta information, you should do
116
+ that by using ordinary key/value pairs:
117
+
118
+ [string with metainfo v1.0|
119
+ <charset> [ISO-8859-1]
120
+ <language> [en]
121
+ <content> [Hello World!]
122
+ ]
123
+
124
+
106
125
  END_OF_EXAMPLE
107
126
 
108
127
  # Error raised by UdatCollection#fetch,
@@ -139,7 +158,7 @@ class Udat
139
158
  # Sets the tag (i.e. type of the content).
140
159
  def tag=(tag)
141
160
  synchronize do
142
- @tag = tag ? tag.to_s : nil
161
+ @tag = tag ? tag.to_s.dup.freeze : nil
143
162
  end
144
163
  return tag
145
164
  end
@@ -179,6 +198,21 @@ class Udat
179
198
  "udat{#{self.encode}}"
180
199
  end
181
200
 
201
+ # Returns self, or a duplicate of self with a different tag set, if an
202
+ # argument is passed.
203
+ def to_udat(tag = KeepTag)
204
+ if tag == KeepTag
205
+ return self
206
+ else
207
+ obj = nil
208
+ synchronize do
209
+ obj = self.dup
210
+ end
211
+ obj.tag = tag
212
+ return obj
213
+ end
214
+ end
215
+
182
216
  # Returns a hash key used by ruby's Hash'es.
183
217
  def hash
184
218
  to_s.hash
@@ -195,45 +229,6 @@ class Udat
195
229
  self.eql? other
196
230
  end
197
231
 
198
- # Casts a value to an Udat object. If two arguments are supplied,
199
- # the first argument is a tag, while the second is the content.
200
- # If just one argument is supplied, then the tag is assumed to be nil,
201
- # and the argument given is the content.
202
- # Interpretation of the content depends on the type: If the content is
203
- # an Array (responds to 'to_ary') an ordered collection will be created,
204
- # if the content is a Hash (responds to 'to_hash'), an unordered
205
- # collection will be created. Otherwise the content will be casted to a
206
- # String with 'to_s' to be stored as a scalar.
207
- # If you pass an Array, each element of that array may be an Array
208
- # of size 2, in which case the 2 entries are used as key and value.
209
- # If an element of the Array is not an Array, it will be used as value
210
- # without an associated key.
211
- # This method is called by Object#to_udat.
212
- def self.construct(*args)
213
- if args.length == 1
214
- tag = nil
215
- content = args[0]
216
- elsif args.length == 2
217
- tag = args[0]
218
- content = args[1]
219
- else
220
- raise ArgumentError, "Wrong number of arguments supplied."
221
- end
222
- if content.kind_of? Udat
223
- if tag
224
- content = content.dup
225
- content.tag = tag
226
- end
227
- return content
228
- elsif content.respond_to? :to_ary
229
- return UdatCollection.new(tag, content.to_ary)
230
- elsif content.respond_to? :to_hash
231
- return UdatCollection.new(tag, content.to_hash.to_a).unordered!
232
- else
233
- return UdatScalar.new(tag, content)
234
- end
235
- end
236
-
237
232
  # Internal parsing function.
238
233
  def self.parse_intern(input, start_pos = 0)
239
234
  string = ""
@@ -306,8 +301,8 @@ class Udat
306
301
  # Parses a given string and returns a structure of Udat objects.
307
302
  #
308
303
  # Note: When parsing UDAT data, no information is gained, whether
309
- # collections are ordered or unordered. After parsing all collections
310
- # will be marked as unordered, until changed.
304
+ # collections are ordered or unordered. After parsing, all collections
305
+ # will be marked as unordered, unless changed later by the application.
311
306
  def self.parse(input)
312
307
  input = input.to_s
313
308
  result, pos = parse_intern(input)
@@ -317,6 +312,44 @@ class Udat
317
312
  return result
318
313
  end
319
314
 
315
+ # Reads an encoded UDAT object from a stream.
316
+ # The object must be enclosed in square brackets.
317
+ def self.read_from_stream(io)
318
+ begin
319
+ char = io.read(1)
320
+ return nil if char.nil? or char.length < 1
321
+ if char == "\\"
322
+ char = io.read(1)
323
+ return nil if char.nil? or char.length < 1
324
+ end
325
+ end while char != "["
326
+ buffer = ""
327
+ level = 1
328
+ while true
329
+ char = io.read(1)
330
+ if char.nil? or char.length < 1
331
+ return EOFError, "Unexpected end of file in UDAT stream."
332
+ end
333
+ if char == "\\"
334
+ buffer << char
335
+ char = io.read(1)
336
+ if char.nil? or char.length < 1
337
+ return EOFError, "Unexpected end of file in UDAT stream."
338
+ end
339
+ elsif char == "[" or char == "<"
340
+ level += 1
341
+ elsif char == "]" or char == ">"
342
+ level -= 1
343
+ end
344
+ if level > 0
345
+ buffer << char
346
+ else
347
+ break
348
+ end
349
+ end
350
+ return parse(buffer)
351
+ end
352
+
320
353
  end
321
354
 
322
355
 
@@ -390,14 +423,7 @@ class UdatCollection < Udat
390
423
  @ordered = true
391
424
  @entries = []
392
425
  require_index_hashes
393
- unless content.nil?
394
- if content.respond_to? :to_ary
395
- content = content.to_ary
396
- else
397
- content = [content]
398
- end
399
- content.each { |entry| self << entry }
400
- end
426
+ content.to_ary.each { |entry| self << entry }
401
427
  end
402
428
 
403
429
  # Deletes the internal index hashes.
@@ -893,9 +919,31 @@ end
893
919
 
894
920
 
895
921
  class Object
896
- # Calls Udat.construct(tag, self).
922
+ # Casts the Object to a nUdatScalar object, optionally with a given tag.
923
+ # Unless overwritten by sub classes, only the string representation (as
924
+ # returned by Object#to_s) will be stored as content in the UdatScalar
925
+ # object.
926
+ def to_udat(tag = nil)
927
+ UdatScalar.new(tag, self)
928
+ end
929
+ end
930
+
931
+ class Array
932
+ # Casts the Array to an UdatCollection object, optionally with a given
933
+ # tag. The UdatCollection object is marked to be ordered. Each element of
934
+ # the array may be an Array of size 2, in which case the 2 entries are
935
+ # used as key and value. If an element of the Array is not an Array, it
936
+ # will be used as value without an associated key.
937
+ def to_udat(tag = nil)
938
+ UdatCollection.new(tag, self)
939
+ end
940
+ end
941
+
942
+ class Hash
943
+ # Casts the Hash to an UdatCollection object, optionally with a given
944
+ # tag. The UdatCollection object is marked to be unordered.
897
945
  def to_udat(tag = nil)
898
- Udat.construct(tag, self)
946
+ UdatCollection.new(tag, self.to_a).unordered!
899
947
  end
900
948
  end
901
949
 
@@ -906,3 +954,10 @@ class String
906
954
  end
907
955
  end
908
956
 
957
+ class IO
958
+ # Calls Udat.read_from_stream(self).
959
+ def read_udat
960
+ Udat.read_from_stream(self)
961
+ end
962
+ end
963
+
metadata CHANGED
@@ -3,7 +3,7 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: udat
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.1.0
6
+ version: 1.1.1
7
7
  date: 2007-05-23 00:00:00 +00:00
8
8
  summary: Parser and generator for UDAT documents, a generic data format similar to XML or YAML.
9
9
  require_paths: