lib/hx.rb in hx-0.7.4 vs lib/hx.rb in hx-0.8.2

- old
+ new

@@ -19,16 +19,16 @@ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -require 'rubygems' require 'thread' require 'set' require 'pathname' require 'tempfile' require 'yaml' +require 'hx/path' module Hx VERSION = (Pathname.new(__FILE__).parent.parent + 'VERSION').read.strip @@ -36,119 +36,105 @@ end class EditingNotSupportedError < RuntimeError end +# minimal complete definition: each_entry_path + get_entry, or each_entry module Filter def edit_entry(path, prototype=nil) raise EditingNotSupportedError, "Editing not supported for #{path}" end - def each_entry_path - each_entry { |path, entry| yield path } + def each_entry_path(selector) + each_entry(selector) { |path, entry| yield path } end - def each_entry - each_entry_path do |path| + def each_entry(selector) + each_entry_path(selector) do |path| begin entry = get_entry(path) rescue NoSuchEntryError next # entries may come and go during the enumeration end yield path, entry end end def get_entry(path) - each_entry do |entry_path, entry| - return entry if entry_path == path + each_entry(Path.literal(path)) do |entry_path, entry| + return entry end raise NoSuchEntryError, path end end class NullInput include Filter - def each_entry + def each_entry(selector) self end end NULL_INPUT = NullInput.new class PathSubset include Filter + def patterns_to_selector(patterns) + patterns.map { |p| Path::parse_pattern(p) }.inject { |a, b| a | b } + end + private :patterns_to_selector + def initialize(input, options) @input = input - @path_filter = Predicate.new(options[:only], options[:except]) + only = patterns_to_selector(Array(options[:only] || [])) + except = patterns_to_selector(Array(options[:except] || [])) + except = ~except if except + if only and except + @selector = only & except + else + @selector = only || except || Path::ALL + end end def edit_entry(path, prototype=nil) - if @path_filter.accept? path + if @selector.accept? path @input.edit_entry(path, prototype) { |text| yield text } else raise EditingNotSupportedError, "Editing not supported for #{path}" end self end - def each_entry_path - @input.each_entry_path do |path| - yield path if @path_filter.accept? path - end + def each_entry_path(selector, &block) + @input.each_entry_path(@selector & selector, &block) self end + def each_entry(selector, &block) + @input.each_entry(@selector & selector, &block) + self + end + def get_entry(path) - raise NoSuchEntryError, path unless @path_filter.accept? path + raise NoSuchEntryError, path unless @selector.accept? path @input.get_entry(path) end end -class PathSubset::Predicate - def initialize(accept, reject) - @accept_re = patterns_to_re(accept) - @reject_re = patterns_to_re(reject) - end - - def accept?(path) - (not @accept_re or path =~ @accept_re) and - (not @reject_re or path !~ @reject_re) - end - - def patterns_to_re(patterns) - return nil if patterns.nil? or patterns.empty? - patterns = Array(patterns) - Regexp.new("(?:#{patterns.map { |p| pattern_to_re(p) }.join("|")})") - end - private :patterns_to_re - - def pattern_to_re(pattern) - "^#{pattern.scan(/(\*\*?|[^*]+)/).map { |s,| - case s - when "**"; ".*" - when "*"; "[^/]*" - else Regexp.quote(s) - end - }}$" - end - private :pattern_to_re -end - class Overlay include Filter def initialize(*inputs) @inputs = inputs end - def each_entry_path + def each_entry_path(selector) seen = Set[] @inputs.each do |input| - input.each_entry_path do |path| + input.each_entry_path(selector) do |path| yield path unless seen.include? path seen.add path end end self @@ -195,12 +181,15 @@ raise EditingNotSupportedError, "Editing not supported for #{path}" unless path @input.edit_entry(path, prototype) { |text| yield text } self end - def each_entry_path - @input.each_entry_path { |path| yield add_circumfix(path) } + def each_entry_path(selector) + @input.each_entry_path(Path::ALL) do |path| + path = add_circumfix(path) + yield path if selector.accept? path + end self end def get_entry(path) path = strip_circumfix(path) @@ -216,14 +205,14 @@ path = add_circumfix(path) @input.edit_entry(path, prototype) { |text| yield text } self end - def each_entry_path - @input.each_entry_path do |path| + def each_entry_path(selector) + @input.each_entry_path(Path::ALL) do |path| path = strip_circumfix(path) - yield path if path + yield path if path and selector.accept? path end self end def get_entry(path) @@ -244,26 +233,26 @@ def edit_entry(path, prototype=nil) @input.edit_entry(path, prototype) { |text| yield text } self end - def each_entry + def each_entry(selector) entries = nil @lock.synchronize do if @entries entries = @entries else entries = [] - @input.each_entry do |path, entry| + @input.each_entry(Path::ALL) do |path, entry| @entries_by_path[path] = entry entries << [path, entry] end @entries = entries end end entries.each do |path, entry| - yield path, entry.dup + yield path, entry.dup if selector.accept? path end self end def get_entry(path) @@ -292,13 +281,13 @@ def edit_entry(path, prototype=nil) @input.edit_entry(path, prototype) { |text| yield text } self end - def each_entry + def each_entry(selector) entries = [] - @input.each_entry do |path, entry| + @input.each_entry(selector) do |path, entry| entries << [path, entry] end unless @key_fields.empty? entries = entries.sort_by do |path, entry| @key_fields.map { |f| entry[f] } @@ -540,11 +529,11 @@ def edit_entry(path, prototype=nil) @combined_output.edit_entry(path, prototype) { |text| yield text } self end - def each_entry_path - @combined_output.each_entry_path { |path| yield path } + def each_entry_path(selector) + @combined_output.each_entry_path(selector) { |path| yield path } self end def get_entry(path) @combined_output.get_entry(path)