Module: Udat

Defined in:
lib/udat.rb

Overview

Copyright © 2007 FlexiGuided GmbH, Berlin

Author: Jan Behrens

Website: www.flexiguided.de/publications.udat.en.html


This module provides data structures to represent nodes of UDAT documents, a data format offering a generic basis for data storage and transmission, while being both easily readable by humans and machines. The format is comparable to formats like XML or YAML, but due to its simplicity is much more easy to parse.

UDAT documents can be generated by converting an Object to a Udat::Node, by calling Object#to_udat, and then encoding them by calling Udat::Node#encode.

UDAT documents can be parsed by calling String#parse_udat.

There are methods providing useful IO functions for UDAT documents: IO#read_udat, IO#write_udat, Udat::Node#rpc and Udat.run_rpc_server.

Defined Under Namespace

Modules: Demo Classes: Collection, Node, ParseError, Scalar, UdatIndexError, UdatPropertyMismatch, UdatTagMismatch, UdatTypeMismatch

Constant Summary collapse

AnyTag =

Special argument used as an argument default, do not use it directly.

Object.new

Class Method Summary collapse

Class Method Details

.escape_string(string) ⇒ Object

Returns an escaped version of a string, where backslashes are preceding certain reserved characters.



54
55
56
# File 'lib/udat.rb', line 54

def escape_string(string)
  string.to_s.gsub /([<>\[\]|~\\])/, "\\\\\\1"
end

.run_rpc_server(listen_on, timeout = 180) ⇒ Object

Waits in an endless loop for incoming connections and runs a new thread for each incoming connection, reads and parses UDAT objects, passes them each to a given block (by calling yield) and writes the result of the called block in form of an encoded UDAT object back to the socket. If the argument “listen_on” is an Integer, it is used as a TCP port number, if the argument is a String, the port being listened on will be determined by a DNS look-up of an _udat-rpc._tcp SRV record. In both cases the TCP socket is bound to all interfaces. Alternatively “listen_on” may be a non Integer object, supplying an “accept” method like TCPServer or UNIXServer, which returns a socket for each incoming connection.



1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
# File 'lib/udat.rb', line 1103

def run_rpc_server(listen_on, timeout = 180)
  unless block_given?
    raise ArgumentError, "No block given for Udat::run_rpc_server call."
  end
  if listen_on.kind_of? String
    Resolv::DNS.open do |dns|
      srv_rr = dns.getresource(
        "_udat-rpc._tcp.#{listen_on}",
        Resolv::DNS::Resource::IN::SRV
      )
      listen_on = srv_rr.port.to_i
    end
  end
  new_server = nil
  begin
    if listen_on.kind_of? Integer
      new_server = TCPServer.new(listen_on)
      server = new_server
    elsif listen_on.respond_to? :accept
      server = listen_on
    elsif listen_on.respond_to? :to_int
      new_server = TCPServer.new(listen_on.to_int)
      server = new_server
    else
      raise ArgumentError,
        "Argument \"listen_on\" passed to Udat::run_rpc_server " <<
        "is not an integer and has no \"accept\" or \"to_int\" method."
    end
    while true
      Thread.new(server.accept) do |socket|
        begin
          while true
            query = nil
            begin
              Timeout.timeout(timeout) do
                begin
                  query = socket.read_udat
                rescue EOFError, ParseError
                  break
                end
              end
            rescue Timeout::Error
            end
            break unless query
            socket.write_udat(yield(query))
          end
        ensure
          socket.close
        end
      end
    end
  ensure
    new_server.close if server
  end
end