# hx/listing/recursiveindex - Recursive index generator # # Copyright (c) 2009-2010 MenTaLguY <mental@rydia.net> # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # 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 'hx' require 'hx/listing/limit' require 'hx/listing/paginate' require 'set' module Hx module Listing class RecursiveIndex include Hx::Filter def self.new(input, options) listing = super(input, options) if options.has_key? :limit listing = Limit.new(listing, :limit => options[:limit]) end if options.has_key? :page_size listing = Paginate.new(listing, :page_size => options[:page_size]) end listing end def initialize(input, options) @input = input end def merge_updated(index, entry) updated = [entry, index].map { |e| e['updated'] }.compact.max index['updated'] = updated if updated end private :merge_updated def each_entry_path(selector) emitted = Set.new @input.each_entry_path(Path::ALL) do |path, entry| components = path.split("/") until components.empty? components.pop index_path = (components + ["index"]).join("/") break if emitted.include? index_path yield index_path if selector.accept_path? index_path emitted.add index_path end end self end def get_entry(path) raise NoSuchEntryError, path unless path =~ %r!^((?:.*/)?)index$! prefix = $1 selector = Path.parse_pattern("#{prefix}**") index = {'items' => []} @input.each_entry(selector) do |child_path, entry| if child_path == path index = entry.merge(index) else index['items'] << {'path' => child_path, 'entry' => entry} end merge_updated(index, entry) end raise NoSuchEntryError, path if index['items'].empty? index end end end end