libs/uci: add luci.model.uci.bind class for easier oop-uci integration
[project/luci.git] / libs / uci / luasrc / model / uci / bind.lua
1 --[[
2 LuCI - UCI utilities for model classes
3
4 Copyright 2009 Jo-Philipp Wich <xm@subsignal.org>
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9
10         http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17
18 ]]--
19
20 local assert, pairs, type = assert, pairs, type
21 local utl = require "luci.util"
22
23 module "luci.model.uci.bind"
24
25 bind = utl.class()
26
27 function bind.__init__(self, config, cursor)
28         assert(config, "call to bind() without config file")
29         self.cfg = config
30         self.uci = cursor
31 end
32
33 function bind.init(self, cursor)
34         assert(cursor, "call to init() without uci cursor")
35         self.uci = cursor
36 end
37
38 function bind.section(self, stype)
39         local x = utl.class(bsection)
40         x.__init__ = function(inst, sid)
41                 assert(self.uci:get(self.cfg, sid) == stype,
42                         "attempt to instantiate bsection(%q) of wrong type, expected %q"
43                         % { sid, stype })
44
45                 inst.bind  = self
46                 inst.stype = stype
47                 inst.sid   = sid
48         end
49         return x
50 end
51
52 function bind.usection(self, stype)
53         local x = utl.class(bsection)
54         x.__init__ = function(inst)
55                 inst.bind  = self
56                 inst.stype = stype
57                 inst.sid   = true
58         end
59         return x()
60 end
61
62 function bind.list(self, list, add, rem)
63         local lookup = { }
64
65         if type(list) == "string" then
66                 local item
67                 for item in list:gmatch("%S+") do
68                         lookup[item] = true
69                 end
70
71         elseif type(list) == "table" then
72                 local item
73                 for _, item in pairs(list) do
74                         lookup[item] = true
75                 end
76         end
77
78         if add then lookup[add] = true end
79         if rem then lookup[rem] = nil  end
80
81         return utl.keys(lookup)
82 end
83
84 function bind.bool(self, v)
85         return ( v == "1" or v == "true" or v == "yes" or v == "on" )
86 end
87
88
89 bsection = utl.class()
90
91 function bsection.uciop(self, op, ...)
92         assert(self.bind and self.bind.uci,
93                 "attempt to use unitialized binding: " .. type(self.sid))
94
95         return op and self.bind.uci[op](self.bind.uci, self.bind.cfg, ...)
96                 or self.bind.uci
97 end
98
99 function bsection.get(self, k, c)
100         local v
101         self:uciop("foreach", self.stype,
102                 function(s)
103                         if type(c) == "table" then
104                                 local ck, cv
105                                 for ck, cv in pairs(c) do
106                                         if s[ck] ~= cv then return true end
107                                 end
108                         elseif type(c) == "string" and s['.name'] ~= c then
109                                 return true
110                         end
111                         if k ~= nil then
112                                 v = s[k]
113                         else
114                                 v = s
115                         end
116                         return false
117                 end)
118         return v
119 end
120
121 function bsection.set(self, k, v, c)
122         local stat
123         self:uciop("foreach", self.stype,
124                 function(s)
125                         if type(c) == "table" then
126                                 local ck, cv
127                                 for ck, cv in pairs(c) do
128                                         if s[ck] ~= cv then return true end
129                                 end
130                         elseif type(c) == "string" and s['.name'] ~= c then
131                                 return true
132                         end
133                         stat = self:uciop("set", c, k, v)
134                         return false
135                 end)
136         return stat or false
137 end
138
139 function bsection.property(self, k, n)
140         self[n or k] = function(c, val)
141                 if val == nil then
142                         return c:get(k, c.sid)
143                 else
144                         return c:set(k, val, c.sid)
145                 end
146         end
147 end
148
149 function bsection.property_bool(self, k, n)
150         self[n or k] = function(c, val)
151                 if val == nil then
152                         return self.bind:bool(c:get(k, c.sid))
153                 else
154                         return c:set(k, self.bind:bool(val) and "1" or "0", c.sid)
155                 end
156         end
157 end
158