udat 1.1.0 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/udat.rb +111 -56
- 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
|
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
|
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,
|
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
|
-
|
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
|
-
#
|
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
|
-
|
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.
|
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:
|