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.
- 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:
|