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