Class: Udat
Overview
Copyright © 2007 FlexiGuided GmbH, Berlin
Author: Jan Behrens
Website: www.flexiguided.de/publications.udat.en.html
Abstract class of an UDAT object. UDAT objects basically consist of a tag and the content. The tag can be a String or be nil. The content is either a scalar value stored as a String, or an ordered/unordered collection of values (where each value can optionally have a key associated with it). Keys and values of collections are always UDAT objects too.
UDAT objects can most easily be constructed from other ruby objects by using the Object#to_udat method.
By calling the method Udat#encode, the UDAT object is encoded in a both easily human readable and easily machine readable format. The output can be later parsed by String#parse_udat, or if it is enclosed in square brackets by IO#read_udat.
Direct Known Subclasses
Defined Under Namespace
Classes: UdatParseError, UdatTagMismatch, UdatTypeMismatch
Constant Summary collapse
- KeepTag =
Special argument passed to Udat#to_udat, if the tag is to be kept.
Object.new
- ExampleDocument =
A string containing an UDAT example document.
<<-'END_OF_EXAMPLE' This file contains several UDAT objects (each of them enclosed in square brackets), serving as an example for the UDAT format: Scalar values: [Hello World!] [UTF-8|Hello World!] This object has a tag "UTF-8". Intepretation of tags is task of the application, there are no standard tags defined. [23] [integer|23] [rational|2/3] The following 7 characters must be escaped with a backslash, when being part of a tag or being part of the content of a scalar: \< \> \[ \] \| \~ \\ Arrays (or sets): [ [1] [2] [3] ] [ [1] [2] Comments are allowed here! (and alomost everywhere) [3] ] [ [person| <firstname>[Max] <lastname>[Mustermann] ] [person| <firstname>[Martin] <lastname>[html|Müller] ] [group| <name>[Sample group] <members> [ [person| <firstname>[Max] <lastname>[Mustermann] ] [person| <firstname>[Martin] <lastname>[html|Müller] ] ] ] ] References like in YAML with &id and *id are not directly supported by UDAT. Empty arrays, sets or maps must contain the ~ character, to avoid ambiguity with scalars: [ ] scalar containing three spaces [ ~ ] empty array [list of numbers| ~ ] empty array, tagged with "list of numbers" [ ~ comment ] empty array with a comment [ comment ~ ] another empty array with a comment [ ~~ ] empty array too (multiple ~ are allowed) It is also allowed to write ~ in non-empty arrays. In that case the ~ symbol is ignored. [~ [1] [2] [3] ] Array containing "1", "2" and "3" Ordered or unordered maps: [ <&> [html|&] <"> [html|"] <\<> [html|<] <\>> [html|>] ] [ <color combination|[red][blue]> [nice] <color combination|[red][magenta]> [ugly] ] [ < <red>[on] <yellow>[off] <green>[off] > [stop] < <red>[on] <yellow>[on] <green>[off] > [attention] < <red>[off] <yellow>[off] <green>[on] > [go] < <red>[off] <yellow>[on] <green>[off] > [prepare to stop] ] Sample configuration file: [sample config v1.0| <locale> [ <language> [de] <timezone> [CET] ] <logging> [ <verbosity> [high] <destination> [file|/var/log/sample.log] ] <network> [ <max connections> [256] <reverse lookups> [yes] ] <access control> [ <allowed> [ [user|martin] [user|max] [group|admins] ] ] ] Don't abuse tags to store complicated meta information like this: WRONG! [string charset=ISO-8859-1 language=EN|Hello World!] WRONG! If you need to store more complicated meta information, you should do that by using ordinary key/value pairs: [string with metainfo v1.0| <charset> [ISO-8859-1] <language> [en] <content> [Hello World!] ] END_OF_EXAMPLE
Instance Attribute Summary collapse
-
#tag ⇒ Object
Tag (i.e. type of the content).
Class Method Summary collapse
-
.escape_string(string) ⇒ Object
Returns an escaped version of a string, where backslashes are preceding certain reserved characters.
-
.parse(input) ⇒ Object
Parses a given string and returns a structure of Udat objects.
-
.read_from_stream(io) ⇒ Object
Reads an encoded UDAT object from a stream.
Instance Method Summary collapse
-
#==(other) ⇒ Object
Same as Udat#eql?, but behaves differently in UdatCollection.
-
#collection? ⇒ Boolean
Returns true, if the UDAT object represents a collection.
-
#encode ⇒ Object
Returns the data (including it’s tag) encoded in the UDAT format.
-
#eql?(other) ⇒ Boolean
Returns true, if class, tag and content (including it’s order in case of a UdatCollection) are matching another object.
-
#hash ⇒ Object
Returns a hash key used by ruby’s Hash’es.
-
#initialize(tag) ⇒ Udat
constructor
Creates a new Udat object with a given tag (which may be nil).
-
#inspect ⇒ Object
Does the same as Udat#encode, but encloses the results in curly brackets and preceds them with the string “udat”.
-
#scalar? ⇒ Boolean
Returns true, if the UDAT object represents a scalar value.
-
#to_s ⇒ Object
Here the method does the same as Udat#encode, but this method is overwritten in UdatScalar!.
-
#to_udat(tag = KeepTag) ⇒ Object
Returns self, or a duplicate of self with a different tag set, if an argument is passed.
-
#write_to_stream(io) ⇒ Object
Encodes an UDAT object and writes it enclosed by square brackets to a stream.
Constructor Details
#initialize(tag) ⇒ Udat
Creates a new Udat object with a given tag (which may be nil). This method is private, Udat#initialize is only called through supercalls.
160 161 162 163 |
# File 'lib/udat.rb', line 160 def initialize(tag) super() self.tag = tag end |
Instance Attribute Details
#tag ⇒ Object
Tag (i.e. type of the content).
177 178 179 |
# File 'lib/udat.rb', line 177 def tag @tag end |
Class Method Details
.escape_string(string) ⇒ Object
Returns an escaped version of a string, where backslashes are preceding certain reserved characters.
167 168 169 |
# File 'lib/udat.rb', line 167 def self.escape_string(string) string.to_s.gsub /([<>\[\]|~\\])/, "\\\\\\1" end |
.parse(input) ⇒ Object
Parses a given string and returns a structure of Udat objects.
Note: When parsing UDAT data, no information is gained, whether collections are ordered or unordered. After parsing, all collections will be marked as unordered, unless changed later by the application.
333 334 335 336 337 338 339 340 |
# File 'lib/udat.rb', line 333 def self.parse(input) input = input.to_s result, pos = parse_intern(input) if pos < input.length raise UdatParseError, "Closing bracket without opening bracket." end return result end |
.read_from_stream(io) ⇒ Object
Reads an encoded UDAT object from a stream. The object must be enclosed in square brackets.
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 |
# File 'lib/udat.rb', line 344 def self.read_from_stream(io) begin begin char = io.read(1) return nil if char.nil? or char.length < 1 if char == "\\" char = io.read(1) return nil if char.nil? or char.length < 1 end end while char != "[" and char != "<" buffer = (char == "[") ? "" : nil level = 1 while true char = io.read(1) if char.nil? or char.length < 1 return EOFError, "Unexpected end of file in UDAT stream." end if char == "\\" buffer << char if buffer char = io.read(1) if char.nil? or char.length < 1 return EOFError, "Unexpected end of file in UDAT stream." end elsif char == "[" or char == "<" level += 1 elsif char == "]" or char == ">" level -= 1 end if level > 0 buffer << char if buffer else break end end end while buffer.nil? return parse(buffer) end |
Instance Method Details
#==(other) ⇒ Object
Same as Udat#eql?, but behaves differently in UdatCollection.
248 249 250 |
# File 'lib/udat.rb', line 248 def ==(other) self.eql? other end |
#collection? ⇒ Boolean
Returns true, if the UDAT object represents a collection.
191 192 193 |
# File 'lib/udat.rb', line 191 def collection? kind_of? UdatCollection end |
#encode ⇒ Object
Returns the data (including it’s tag) encoded in the UDAT format.
Note: The UDAT format doesn’t contain information, whether contained collections are ordered or unordered. This information is lost during the encoding process, and has to be restored in an application specific way, if neccessary.
201 202 203 204 205 206 207 208 209 |
# File 'lib/udat.rb', line 201 def encode synchronize do if tag return "#{escape_string tag}|#{encoded_content}" else return encoded_content end end end |
#eql?(other) ⇒ Boolean
Returns true, if class, tag and content (including it’s order in case of a UdatCollection) are matching another object.
242 243 244 245 246 |
# File 'lib/udat.rb', line 242 def eql?(other) self.class == other.class and self.tag == other.tag and self.to_s == other.to_s end |
#hash ⇒ Object
Returns a hash key used by ruby’s Hash’es.
237 238 239 |
# File 'lib/udat.rb', line 237 def hash to_s.hash end |
#inspect ⇒ Object
Does the same as Udat#encode, but encloses the results in curly brackets and preceds them with the string “udat”.
217 218 219 |
# File 'lib/udat.rb', line 217 def inspect "udat{#{self.encode}}" end |
#scalar? ⇒ Boolean
Returns true, if the UDAT object represents a scalar value.
187 188 189 |
# File 'lib/udat.rb', line 187 def scalar? kind_of? UdatScalar end |
#to_s ⇒ Object
Here the method does the same as Udat#encode, but this method is overwritten in UdatScalar!
212 213 214 |
# File 'lib/udat.rb', line 212 def to_s encode end |
#to_udat(tag = KeepTag) ⇒ Object
Returns self, or a duplicate of self with a different tag set, if an argument is passed.
223 224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/udat.rb', line 223 def to_udat(tag = KeepTag) if tag == KeepTag return self else obj = nil synchronize do obj = self.dup end obj.tag = tag return obj end end |
#write_to_stream(io) ⇒ Object
Encodes an UDAT object and writes it enclosed by square brackets to a stream.
384 385 386 387 |
# File 'lib/udat.rb', line 384 def write_to_stream(io) io << "[#{self.to_udat}]" return self end |