Class: Hike::Index

### Home Classes Methods

### In Files

- lib/hike/index.rb

### Parent

Object

### Methods

- ::new
- #build_pattern_for
- #entries
- #extract_options!
- #find
- #find_aliases_for
- #find_in_base_path
- #find_in_paths
- #index
- #match
- #paths_contain?
- #pattern_for
- #relative?
- #root
- #sort_matches
- #stat

### Class/Module Index

Quicksearch

- Hike
- Hike::Extensions
- Hike::Index
- Hike::NormalizedArray
- Hike::Paths
- Hike::Trail

No matching classes.

# Hike::Index

`Index` is an internal cached variant of `Trail`. It assumes the file system does not change between `find` calls. All `stat` and `entries` calls are cached for the lifetime of the `Index` object.

### Attributes

aliases[R]

`Index#aliases` is an immutable `Hash` mapping an extension to an `Array` of aliases.

extensions[R]

`Index#extensions` is an immutable `Extensions` collection.

paths[R]

`Index#paths` is an immutable `Paths` collection.

### Public Class Methods

new(root, paths, extensions, aliases) click to toggle source

`Index.new` is an internal method. Instead of constructing it directly, create a `Trail` and call `Trail#index`.

    # File lib/hike/index.rb, line 20
    def initialize(root, paths, extensions, aliases)
      @root = root

      # Freeze is used here so an error is throw if a mutator method
      # is called on the array. Mutating `@paths`, `@extensions`, or
      # `@aliases` would have unpredictable results.
      @paths      = paths.dup.freeze
      @extensions = extensions.dup.freeze
      @aliases    = aliases.inject({}) { |h, (k, a)|
                      h[k] = a.dup.freeze; h
                   }.freeze
      @pathnames  = paths.map { |path| Pathname.new(path) }

      @stats    = {}
      @entries  = {}
      @patterns = {}
    end

### Public Instance Methods

entries(path) click to toggle source

A cached version of `Dir.entries` that filters out `.` files and `~` swap files. Returns an empty `Array` if the directory does not exist.

    # File lib/hike/index.rb, line 78
    def entries(path)
      @entries[path.to_s] ||= begin
        pathname = Pathname.new(path)
        if pathname.directory?
          pathname.entries.reject { |entry| entry.to_s =~ /^\.|~$|^\#.*\#$/ }.sort
        else
          []
        end
      end
    end

find(*logical_paths, &block) click to toggle source

The real implementation of `find`. `Trail#find` generates a one time index and delegates here.

See `Trail#find` for usage.

    # File lib/hike/index.rb, line 52
    def find(*logical_paths, &block)
      if block_given?
        options = extract_options!(logical_paths)
        base_path = Pathname.new(options[:base_path] || @root)

        logical_paths.each do |logical_path|
          logical_path = Pathname.new(logical_path.sub(/^\//, ''))

          if relative?(logical_path)
            find_in_base_path(logical_path, base_path, &block)
          else
            find_in_paths(logical_path, &block)
          end
        end

        nil
      else
        find(*logical_paths) do |path|
          return path
        end
      end
    end

index() click to toggle source

`Index#index` returns `self` to be compatable with the `Trail` interface.

    # File lib/hike/index.rb, line 44
    def index
      self
    end

root() click to toggle source

`Index#root` returns root path as a `String`. This attribute is immutable.

    # File lib/hike/index.rb, line 39
    def root
      @root.to_s
    end

stat(path) click to toggle source

A cached version of `File.stat`. Returns nil if the file does not exist.

    # File lib/hike/index.rb, line 91
    def stat(path)
      key = path.to_s
      if @stats.key?(key)
        @stats[key]
      elsif File.exist?(path)
        @stats[key] = File.stat(path)
      else
        @stats[key] = nil
      end
    end

### Protected Instance Methods

build_pattern_for(basename) click to toggle source

Returns a `Regexp` that matches the allowed extensions.

    pattern_for("index.html") #=> /^index(.html|.htm)(.builder|.erb)*$/

    # File lib/hike/index.rb, line 162
    def build_pattern_for(basename)
      extname = basename.extname
      aliases = find_aliases_for(extname)

      if aliases.any?
        basename = basename.basename(extname)
        aliases  = [extname] + aliases
        aliases_pattern = aliases.map { |e| Regexp.escape(e) }.join("|")
        basename_re = Regexp.escape(basename.to_s) + "(?:#{aliases_pattern})"
      else
        basename_re = Regexp.escape(basename.to_s)
      end

      extension_pattern = extensions.map { |e| Regexp.escape(e) }.join("|")
      /^#{basename_re}(?:#{extension_pattern})*$/
    end

extract_options!(arguments) click to toggle source

    # File lib/hike/index.rb, line 103
    def extract_options!(arguments)
      arguments.last.is_a?(Hash) ? arguments.pop.dup : {}
    end

find_aliases_for(extension) click to toggle source

    # File lib/hike/index.rb, line 199
    def find_aliases_for(extension)
      @aliases.inject([]) do |aliases, (key, value)|
        aliases.push(key) if value == extension
        aliases
      end
    end

find_in_base_path(logical_path, base_path, &block) click to toggle source

Finds relative logical path, `../test/test_trail`. Requires a `base_path` for reference.

    # File lib/hike/index.rb, line 121
    def find_in_base_path(logical_path, base_path, &block)
      candidate = base_path.join(logical_path)
      dirname, basename = candidate.split
      match(dirname, basename, &block) if paths_contain?(dirname)
    end

find_in_paths(logical_path, &block) click to toggle source

Finds logical path across all `paths`

    # File lib/hike/index.rb, line 112
    def find_in_paths(logical_path, &block)
      dirname, basename = logical_path.split
      @pathnames.each do |base_path|
        match(base_path.join(dirname), basename, &block)
      end
    end

match(dirname, basename) click to toggle source

Checks if the path is actually on the file system and performs any syscalls if necessary.

    # File lib/hike/index.rb, line 129
    def match(dirname, basename)
      # Potential `entries` syscall
      matches = entries(dirname)

      pattern = pattern_for(basename)
      matches = matches.select { |m| m.to_s =~ pattern }

      sort_matches(matches, basename).each do |path|
        pathname = dirname.join(path)

        # Potential `stat` syscall
        stat = stat(pathname)

        # Exclude directories
        if stat && stat.file?
          yield pathname.to_s
        end
      end
    end

paths_contain?(dirname) click to toggle source

Returns true if `dirname` is a subdirectory of any of the `paths`

    # File lib/hike/index.rb, line 150
    def paths_contain?(dirname)
      paths.any? { |path| dirname.to_s[0, path.length] == path }
    end

pattern_for(basename) click to toggle source

Cache results of `build_pattern_for`

    # File lib/hike/index.rb, line 155
    def pattern_for(basename)
      @patterns[basename] ||= build_pattern_for(basename)
    end

relative?(logical_path) click to toggle source

    # File lib/hike/index.rb, line 107
    def relative?(logical_path)
      logical_path.to_s =~ /^\.\.?\//
    end

sort_matches(matches, basename) click to toggle source

Sorts candidate matches by their extension priority. Extensions in the front of the `extensions` carry more weight.

    # File lib/hike/index.rb, line 182
    def sort_matches(matches, basename)
      aliases = find_aliases_for(basename.extname)

      matches.sort_by do |match|
        extnames = match.sub(basename.to_s, '').to_s.scan(/\.[^.]+/)
        extnames.inject(0) do |sum, ext|
          if i = extensions.index(ext)
            sum + i + 1
          elsif i = aliases.index(ext)
            sum + i + 11
          else
            sum
          end
        end
      end
    end

[Validate]

Generated with the Darkfish Rdoc Generator 2.