lib/rvc/fs.rb in rvc-1.1.0 vs lib/rvc/fs.rb in rvc-1.2.0

- old
+ new

@@ -50,11 +50,13 @@ end class FS attr_reader :root, :loc, :marks - MARK_REGEX = /^~(?:([\d\w]*|~|@))$/ + MARK_PATTERN = /^~(?:([\d\w]*|~|@))$/ + REGEX_PATTERN = /^%/ + GLOB_PATTERN = /\*/ def initialize root @root = root @loc = Location.new root @marks = {} @@ -66,58 +68,81 @@ def display_path @loc.path * '/' end - def lookup path - (lookup_loc(path) || return).obj - end - - def cd path - new_loc = lookup_loc(path) or return false + def cd new_loc mark '~', @loc @loc = new_loc - true end + def lookup path + lookup_loc(path).map(&:obj) + end + def lookup_loc path els, absolute, trailing_slash = Path.parse path base_loc = absolute ? Location.new(@root) : @loc traverse(base_loc, els) end - def traverse base_loc, els - loc = base_loc.dup - els.each_with_index do |el,i| - case el - when '.' - when '..' - loc.pop unless loc.obj == @root - when '...' - loc.push(el, loc.obj.parent) unless loc.obj == @root - when MARK_REGEX - return unless i == 0 - loc = @marks[$1] or return - loc = loc.dup + def traverse_one loc, el, first + case el + when '.' + [loc] + when '..' + loc.pop unless loc.obj == @root + [loc] + when '...' + loc.push(el, loc.obj.parent) unless loc.obj == @root + [loc] + when MARK_PATTERN + return unless first + loc = @marks[$1] or return [] + [loc.dup] + when REGEX_PATTERN + regex = Regexp.new($') + loc.obj.children. + select { |k,v| k =~ regex }. + map { |k,v| loc.dup.tap { |x| x.push(k, v) } } + when GLOB_PATTERN + regex = glob_to_regex el + loc.obj.children. + select { |k,v| k =~ regex }. + map { |k,v| loc.dup.tap { |x| x.push(k, v) } } + else + # XXX check for ambiguous child + if first and el =~ /^\d+$/ and @marks.member? el + loc = @marks[el].dup else - # XXX check for ambiguous child - if i == 0 and el =~ /^\d+$/ and @marks.member? el - loc = @marks[el].dup - else - x = loc.obj.traverse_one(el) or return - loc.push el, x - end + x = loc.obj.traverse_one(el) or return [] + loc.push el, x end + [loc] end - loc end + # Starting from base_loc, traverse each path element in els. Since the path + # may contain wildcards, this function returns a list of matches. + def traverse base_loc, els + locs = [base_loc.dup] + els.each_with_index do |el,i| + locs.map! { |loc| traverse_one loc, el, i==0 } + locs.flatten! + end + locs + end + def mark key, loc if loc == nil @marks.delete key else @marks[key] = loc end + end + + def glob_to_regex str + Regexp.new "^#{Regexp.escape(str.gsub('*', "\0")).gsub("\0", ".*")}$" end end end