Wed, 17 Sep 2008 22:20:08 +0300
Some docs written by Thorns. Need reviewing.
23 | 1 | local t_insert = table.insert; |
2 | local t_remove = table.remove; | |
3 | local s_format = string.format; | |
4 | local tostring = tostring; | |
5 | local setmetatable = setmetatable; | |
6 | local pairs = pairs; | |
7 | local ipairs = ipairs; | |
8 | local type = type; | |
9 | local s_gsub = string.gsub; | |
10 | module "stanza" | |
11 | ||
12 | stanza_mt = {}; | |
13 | stanza_mt.__index = stanza_mt; | |
14 | ||
15 | function stanza(name, attr) | |
16 | local stanza = { name = name, attr = attr or {}, tags = {}, last_add = {}}; | |
17 | return setmetatable(stanza, stanza_mt); | |
18 | end | |
19 | ||
20 | function stanza_mt:iq(attrs) | |
21 | return self + stanza("iq", attrs) | |
22 | end | |
23 | function stanza_mt:message(attrs) | |
24 | return self + stanza("message", attrs) | |
25 | end | |
26 | function stanza_mt:presence(attrs) | |
27 | return self + stanza("presence", attrs) | |
28 | end | |
29 | function stanza_mt:query(xmlns) | |
30 | return self:tag("query", { xmlns = xmlns }); | |
31 | end | |
32 | function stanza_mt:tag(name, attrs) | |
33 | local s = stanza(name, attrs); | |
34 | (self.last_add[#self.last_add] or self):add_child(s); | |
35 | t_insert(self.last_add, s); | |
36 | return self; | |
37 | end | |
38 | ||
39 | function stanza_mt:text(text) | |
40 | (self.last_add[#self.last_add] or self):add_child(text); | |
41 | return self; | |
42 | end | |
43 | ||
44 | function stanza_mt:up() | |
45 | t_remove(self.last_add); | |
46 | return self; | |
47 | end | |
48 | ||
49 | function stanza_mt:add_child(child) | |
50 | if type(child) == "table" then | |
51 | t_insert(self.tags, child); | |
52 | end | |
53 | t_insert(self, child); | |
54 | end | |
55 | ||
56 | function stanza_mt:child_with_name(name) | |
57 | for _, child in ipairs(self) do | |
58 | if child.name == name then return child; end | |
59 | end | |
60 | end | |
61 | ||
62 | function stanza_mt:children() | |
63 | local i = 0; | |
64 | return function (a) | |
65 | i = i + 1 | |
66 | local v = a[i] | |
67 | if v then return v; end | |
68 | end, self, i; | |
69 | ||
70 | end | |
71 | function stanza_mt:childtags() | |
72 | local i = 0; | |
73 | return function (a) | |
74 | i = i + 1 | |
75 | local v = self.tags[i] | |
76 | if v then return v; end | |
77 | end, self.tags[1], i; | |
78 | ||
79 | end | |
80 | ||
81 | do | |
82 | local xml_entities = { ["'"] = "'", ["\""] = """, ["<"] = "<", [">"] = ">", ["&"] = "&" }; | |
83 | function xml_escape(s) return s_gsub(s, "['&<>\"]", xml_entities); end | |
84 | end | |
85 | ||
86 | local xml_escape = xml_escape; | |
87 | ||
88 | function stanza_mt.__tostring(t) | |
89 | local children_text = ""; | |
90 | for n, child in ipairs(t) do | |
91 | if type(child) == "string" then | |
92 | children_text = children_text .. xml_escape(child); | |
93 | else | |
94 | children_text = children_text .. tostring(child); | |
95 | end | |
96 | end | |
97 | ||
98 | local attr_string = ""; | |
99 | if t.attr then | |
100 | for k, v in pairs(t.attr) do if type(k) == "string" then attr_string = attr_string .. s_format(" %s='%s'", k, tostring(v)); end end | |
101 | end | |
102 | ||
103 | return s_format("<%s%s>%s</%s>", t.name, attr_string, children_text, t.name); | |
104 | end | |
105 | ||
106 | function stanza_mt.__add(s1, s2) | |
107 | return s1:add_child(s2); | |
108 | end | |
109 | ||
110 | ||
111 | do | |
112 | local id = 0; | |
113 | function new_id() | |
114 | id = id + 1; | |
115 | return "lx"..id; | |
116 | end | |
117 | end | |
118 | ||
119 | function message(attr, body) | |
120 | if not body then | |
121 | return stanza("message", attr); | |
122 | else | |
123 | return stanza("message", attr):tag("body"):text(body); | |
124 | end | |
125 | end | |
126 | function iq(attr) | |
127 | if attr and not attr.id then attr.id = new_id(); end | |
128 | return stanza("iq", attr or { id = new_id() }); | |
129 | end | |
130 | ||
131 | function reply(orig) | |
132 | return stanza(orig.name, orig.attr and { to = orig.attr.from, from = orig.attr.to, id = orig.attr.id, type = ((orig.name == "iq" and "result") or nil) }); | |
133 | end | |
134 | ||
135 | function presence(attr) | |
136 | return stanza("presence", attr); | |
137 | end | |
138 |