class Patrun
Public Class Methods
new(custom = nil)
click to toggle source
# File lib/patrun.rb 4 def initialize(custom = nil) 5 @top = {} 6 @custom = custom 7 end
Public Instance Methods
add(pat, data)
click to toggle source
# File lib/patrun.rb 10 def add(pat, data) 11 12 customizer = nil 13 if @custom 14 customizer = @custom.call(self, pat, data) 15 end 16 17 pat = pat.inject({}){|memo,(k,v)| memo[k.to_sym] = v.to_s; memo} 18 19 keys = pat.keys.sort() 20 21 keymap = @top 22 valmap = nil 23 24 i = 0 25 while i < keys.length 26 key = keys[i] 27 val = pat[keys[i]] 28 29 if nil == val 30 next 31 end 32 33 valmap = keymap[:v] 34 if valmap && key == keymap[:k] 35 keymap = valmap[val] || (valmap[val] = {}) 36 37 elsif !keymap[:k] 38 keymap[:k] = key 39 40 keymap[:v] = {} 41 42 keymap = keymap[:v][val] = {} 43 44 else 45 if key < keymap[:k] 46 curv = keymap[:v] 47 curs = keymap[:s] 48 keymap[:v] = {} 49 keymap[:s] = {:k => keymap[:k], :v => curv, :s => curs} 50 51 keymap[:k] = key 52 keymap = keymap[:v][val] = {} 53 else 54 valmap = keymap[:v] 55 keymap = keymap[:s] || (keymap[:s] = {}) 56 i-= 1 57 end 58 end 59 i += 1 60 end 61 62 if data != nil && keymap 63 keymap[:d] = data 64 if customizer 65 keymap[:f] = isFunction(customizer) ? customizer : (customizer.class == Hash ? customizer[:find] : false) 66 if (customizer.class == Hash) 67 keymap[:r] = isFunction(customizer[:remove]) ? customizer[:remove] : nil 68 end 69 end 70 end 71 72 self 73 end
find(pat, exact = false)
click to toggle source
# File lib/patrun.rb 81 def find(pat, exact = false) 82 83 if nil == pat 84 return nil 85 end 86 87 pat = pat.inject({}){|memo,(k,v)| memo[k.to_sym] = v.to_s; memo} 88 89 keymap = @top 90 data = @top[:d] || nil 91 finalfind = @top[:f] 92 key = nil 93 stars = [] 94 foundkeys = {} 95 patlen = pat.keys.length 96 97 98 loop do 99 key = keymap[:k] 100 101 if keymap[:v] 102 nextkeymap = keymap[:v][pat[key]] 103 if nextkeymap 104 foundkeys[key] = true 105 106 if keymap[:s] 107 stars.push(keymap[:s]) 108 end 109 110 data = nil == nextkeymap[:d] ? nil : nextkeymap[:d] 111 finalfind = nextkeymap[:f] 112 keymap = nextkeymap 113 114 else 115 keymap = keymap[:s] 116 end 117 118 else 119 keymap = nil 120 end 121 122 if nil == keymap && nil == data && 0 < stars.length 123 keymap = stars.pop() 124 end 125 126 break if !keymap 127 end 128 129 # special case for default with no properties 130 if nil == data && 0 == patlen && nil != @top[:d] 131 data = top[:d] 132 finalfind = top[:f] 133 end 134 135 if exact && foundkeys.keys.length != patlen 136 data = nil 137 end 138 139 if finalfind 140 data = finalfind.call(self, pat, data) 141 end 142 143 data 144 end
findexact(pat)
click to toggle source
# File lib/patrun.rb 77 def findexact(pat) 78 find(pat, true) 79 end
inspect()
click to toggle source
# File lib/patrun.rb 233 def inspect 234 self.toString() 235 end
list(pat = nil, exact = false)
click to toggle source
values can be verbatim, glob, or array of globs
# File lib/patrun.rb 191 def list(pat = nil, exact = false) 192 193 acc = [] 194 195 if @top[:d] 196 item = {:match => {}, 197 :data => @top[:d]} 198 if @top[:f] != nil 199 item[:find] = @top[:f] 200 end 201 acc.push(item) 202 end 203 204 if pat != nil 205 pat = pat.inject({}){|memo,(k,v)| memo[k.to_sym] = v.to_s; memo} 206 end 207 descend(pat, exact, @top, {}, merge({}, pat), acc) 208 209 210 acc 211 end
remove(pat)
click to toggle source
# File lib/patrun.rb 146 def remove(pat) 147 148 keymap = @top 149 data = nil 150 key = nil 151 path = [] 152 153 pat = pat.inject({}){|memo,(k,v)| memo[k.to_sym] = v.to_s; memo} 154 155 loop do 156 key = keymap[:k] 157 158 if keymap[:v] 159 nextkeymap = keymap[:v][pat[key]] 160 if nextkeymap 161 path.push({:km => keymap,:v => pat[key]}) 162 data = nextkeymap[:d] 163 keymap = nextkeymap 164 165 else 166 keymap = keymap[:s] 167 end 168 169 else 170 keymap = nil 171 end 172 173 break if !keymap 174 end 175 176 if nil != data 177 part = path[path.length-1] 178 if part && part[:km] && part[:km][:v] 179 point = part[:km][:v][part[:v]] 180 if !point[:r] || point[:r].call(self, pat, point[:d]) 181 point.delete(:d) 182 end 183 end 184 end 185 end
toJSON()
click to toggle source
# File lib/patrun.rb 238 def toJSON() 239 240 @top.to_json 241 242 end
toString(dstr = nil, tree = false)
click to toggle source
# File lib/patrun.rb 214 def toString(dstr = nil, tree = false) 215 defaultFormat = Proc.new { | d | 216 isFunction(d) ? "<#{d}>" : "<#{d}>" 217 } 218 219 tree = isBoolean(dstr) ? dstr : tree 220 tree = nil == tree ? false : tree 221 222 dstr = isFunction(dstr) ? dstr : defaultFormat 223 224 str = [] 225 o = [] 226 227 walk(@top,o,0,[], str, dstr) 228 229 return tree ? o.join('') : str.join("\n") 230 end
Private Instance Methods
deepCopy(o)
click to toggle source
# File lib/patrun.rb 364 def deepCopy(o) 365 Marshal.load(Marshal.dump(o)) 366 end
descend(pat, exact, keymap, match, missing, acc)
click to toggle source
# File lib/patrun.rb 255 def descend(pat, exact, keymap, match, missing, acc) 256 257 if keymap[:v] 258 key = keymap[:k] 259 patVal = pat ? (nil == pat[key] ? ( exact ? nil : '*' ) : pat[key]) : '*' 260 261 itermatch = merge({}, match) 262 itermissing = merge({}, missing) 263 nextkeymap = nil 264 265 266 for val in keymap[:v].keys 267 268 if gexval(patVal, val) 269 270 valitermatch = deepCopy(itermatch) 271 valitermatch[key] = val 272 273 valitermissing = merge({}, itermissing) 274 valitermissing.delete(key) 275 276 nextkeymap = keymap[:v][val] 277 278 if 0 == valitermissing.keys.length && 279 nextkeymap && 280 nextkeymap[:d] 281 282 item = {:match => valitermatch, 283 :data => nextkeymap[:d]} 284 285 if nextkeymap[:f] != nil 286 item[:find] = nextkeymap[:f] 287 end 288 289 acc.push(item) 290 end 291 292 if nextkeymap && nextkeymap[:v] 293 294 descend(pat, exact, 295 nextkeymap, 296 merge({}, valitermatch), 297 merge({}, valitermissing), 298 acc) 299 end 300 end 301 end 302 303 nextkeymap = keymap[:s] 304 if nextkeymap 305 descend(pat, exact, 306 nextkeymap, 307 merge({}, itermatch), 308 merge({}, itermissing), 309 acc) 310 end 311 end 312 end
escregexp(restr)
click to toggle source
# File lib/patrun.rb 407 def escregexp(restr) 408 if restr 409 restr.to_s.gsub(/[-\[\]{}()*+?.,\\^$|#\s]/) { "\\#{$&}" } 410 else 411 "" 412 end 413 end
gexval(pattern, value)
click to toggle source
# File lib/patrun.rb 384 def gexval(pattern, value) 385 386 387 pattern = escregexp(pattern) 388 389 # use [\s\S] instead of . to match newlines 390 pattern = pattern.gsub(/\\\*/,'[\\s\\S]*') 391 pattern = pattern.gsub(/\\\?/,'[\\s\\S]') 392 393 # escapes ** and *? 394 pattern = pattern.gsub(/\[\\s\\S\]\*\[\\s\\S\]\*/,'\\\*') 395 pattern = pattern.gsub(/\[\\s\\S\]\*\[\\s\\S\]/,'\\\?') 396 397 pattern = "^#{pattern}$" 398 399 if value.to_s.match(pattern) != nil 400 true 401 else 402 false 403 end 404 405 end
indent(o,d)
click to toggle source
# File lib/patrun.rb 248 def indent(o,d) 249 d.times do 250 o.push(' ') 251 end 252 end
isBoolean(obj)
click to toggle source
# File lib/patrun.rb 354 def isBoolean(obj) 355 356 if obj != nil && obj.class == TrueClass || obj.class == FalseClass 357 358 true 359 else 360 false 361 end 362 end
isFunction(param)
click to toggle source
# File lib/patrun.rb 368 def isFunction(param) 369 if param != nil && param.class == Proc 370 true 371 else 372 false 373 end 374 end
merge(source, destination)
click to toggle source
# File lib/patrun.rb 376 def merge(source, destination) 377 if destination != nil 378 source.merge(destination) 379 else 380 source 381 end 382 end
walk(n,o,counter,vs,str, dstr)
click to toggle source
# File lib/patrun.rb 314 def walk(n,o,counter,vs,str, dstr) 315 316 if nil != n[:d] 317 indent(o,counter) 318 o.push(dstr.call(n[:d])) 319 320 str.push("#{vs.join(', ')} -> #{dstr.call(n[:d])}") 321 end 322 323 if n[:k] 324 o.push("\n") 325 indent(o,counter) 326 o.push("#{n[:k]}:") 327 end 328 329 if n[:v] 330 counter =+ 1 331 for p in n[:v].keys 332 o.push("\n") 333 indent(o,counter) 334 o.push("#{p} ->") 335 336 vsc = deepCopy(vs) 337 vsc.push("#{n[:k]}=#{p}") 338 339 walk(n[:v][p],o,counter + 1,vsc,str,dstr) 340 end 341 342 if n[:s] 343 o.push("\n") 344 indent(o,counter) 345 o.push('* ->') 346 347 vsc = deepCopy(vs) 348 walk(n[:s],o,counter + 1,vsc,str,dstr) 349 end 350 end 351 end