udat 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
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: