hike-2.1.3/0000755000004100000410000000000013301515423012462 5ustar www-datawww-datahike-2.1.3/README.md0000644000004100000410000000227013301515423013742 0ustar www-datawww-dataHike ==== Hike is a Ruby library for finding files in a set of paths. Use it to implement search paths, load paths, and the like. # Examples Find Ruby files in this project: trail = Hike::Trail.new "/Users/sam/Projects/hike" trail.append_extension ".rb" trail.append_paths "lib", "test" trail.find "hike/trail" # => "/Users/sam/Projects/hike/lib/hike/trail.rb" trail.find "test_trail" # => "/Users/sam/Projects/hike/test/test_trail.rb" Explore your Ruby load path: trail = Hike::Trail.new "/" trail.append_extensions ".rb", ".bundle" trail.append_paths *$: trail.find "net/http" # => "/Users/sam/.rvm/rubies/ree-1.8.7-2010.02/lib/ruby/1.8/net/http.rb" trail.find "strscan" # => "/Users/sam/.rvm/rubies/ree-1.8.7-2010.02/lib/ruby/1.8/i686-darwin10.4.0/strscan.bundle" Explore your shell path: trail = Hike::Trail.new "/" trail.append_paths *ENV["PATH"].split(":") trail.find "ls" # => "/bin/ls" trail.find "gem" # => "/Users/sam/.rvm/rubies/ree-1.8.7-2010.02/bin/gem" # Installation $ gem install hike # License Copyright (c) 2011 Sam Stephenson. Released under the MIT license. See `LICENSE` for details. hike-2.1.3/LICENSE0000644000004100000410000000204213301515423013465 0ustar www-datawww-dataCopyright (c) 2014 Sam Stephenson 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. hike-2.1.3/hike.gemspec0000644000004100000410000000274313301515423014755 0ustar www-datawww-data######################################################### # This file has been automatically generated by gem2tgz # ######################################################### # -*- encoding: utf-8 -*- # stub: hike 2.1.3 ruby lib Gem::Specification.new do |s| s.name = "hike".freeze s.version = "2.1.3" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Sam Stephenson".freeze] s.date = "2014-04-25" s.description = "A Ruby library for finding files in a set of paths.".freeze s.email = ["sstephenson@gmail.com".freeze] s.files = ["LICENSE".freeze, "README.md".freeze, "lib/hike.rb".freeze, "lib/hike/cached_trail.rb".freeze, "lib/hike/extensions.rb".freeze, "lib/hike/fileutils.rb".freeze, "lib/hike/normalized_array.rb".freeze, "lib/hike/paths.rb".freeze, "lib/hike/trail.rb".freeze] s.homepage = "http://github.com/sstephenson/hike".freeze s.licenses = ["MIT".freeze] s.required_ruby_version = Gem::Requirement.new(">= 1.9.3".freeze) s.rubygems_version = "2.5.2.1".freeze s.summary = "Find files in a set of paths".freeze if s.respond_to? :specification_version then s.specification_version = 4 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, [">= 0"]) end else s.add_dependency(%q.freeze, [">= 0"]) end end hike-2.1.3/lib/0000755000004100000410000000000013301515423013230 5ustar www-datawww-datahike-2.1.3/lib/hike/0000755000004100000410000000000013301515423014150 5ustar www-datawww-datahike-2.1.3/lib/hike/fileutils.rb0000644000004100000410000000105113301515423016472 0ustar www-datawww-datamodule Hike module FileUtils extend self # Like `File.stat`. Returns nil if the file does not exist. def stat(path) if File.exist?(path) File.stat(path.to_s) else nil end end # A version of `Dir.entries` that filters out `.` files and `~` swap files. # Returns an empty `Array` if the directory does not exist. def entries(path) if File.directory?(path) Dir.entries(path).reject { |entry| entry =~ /^\.|~$|^\#.*\#$/ }.sort else [] end end end end hike-2.1.3/lib/hike/trail.rb0000644000004100000410000001240213301515423015607 0ustar www-datawww-datarequire 'pathname' require 'hike/cached_trail' require 'hike/extensions' require 'hike/paths' module Hike # `Trail` is the public container class for holding paths and extensions. class Trail include FileUtils # `Trail#paths` is a mutable `Paths` collection. # # trail = Hike::Trail.new # trail.paths.push "~/Projects/hike/lib", "~/Projects/hike/test" # # The order of the paths is significant. Paths in the beginning of # the collection will be checked first. In the example above, # `~/Projects/hike/lib/hike.rb` would shadow the existent of # `~/Projects/hike/test/hike.rb`. attr_reader :paths # `Trail#extensions` is a mutable `Extensions` collection. # # trail = Hike::Trail.new # trail.paths.push "~/Projects/hike/lib" # trail.extensions.push ".rb" # # Extensions allow you to find files by just their name omitting # their extension. Is similar to Ruby's require mechanism that # allows you to require files with specifiying `foo.rb`. attr_reader :extensions # `Trail#aliases` is a mutable `Hash` mapping an extension to # an `Array` of aliases. # # trail = Hike::Trail.new # trail.paths.push "~/Projects/hike/site" # trail.aliases['.htm'] = 'html' # trail.aliases['.xhtml'] = 'html' # trail.aliases['.php'] = 'html' # # Aliases provide a fallback when the primary extension is not # matched. In the example above, a lookup for "foo.html" will # check for the existence of "foo.htm", "foo.xhtml", or "foo.php". attr_reader :aliases # A Trail accepts an optional root path that defaults to your # current working directory. Any relative paths added to # `Trail#paths` will expanded relative to the root. def initialize(root = ".") @root = Pathname.new(root).expand_path @paths = Paths.new(@root) @extensions = Extensions.new @aliases = {} end # `Trail#root` returns root path as a `String`. This attribute is immutable. def root @root.to_s end # Prepend `path` to `Paths` collection def prepend_paths(*paths) self.paths.unshift(*paths) end alias_method :prepend_path, :prepend_paths # Append `path` to `Paths` collection def append_paths(*paths) self.paths.push(*paths) end alias_method :append_path, :append_paths # Remove `path` from `Paths` collection def remove_path(path) self.paths.delete(path) end # Prepend `extension` to `Extensions` collection def prepend_extensions(*extensions) self.extensions.unshift(*extensions) end alias_method :prepend_extension, :prepend_extensions # Append `extension` to `Extensions` collection def append_extensions(*extensions) self.extensions.push(*extensions) end alias_method :append_extension, :append_extensions # Remove `extension` from `Extensions` collection def remove_extension(extension) self.extensions.delete(extension) end # Alias `new_extension` to `old_extension` def alias_extension(new_extension, old_extension) aliases[normalize_extension(new_extension)] = normalize_extension(old_extension) end # Remove the alias for `extension` def unalias_extension(extension) aliases.delete(normalize_extension(extension)) end # `Trail#find` returns a the expand path for a logical path in the # path collection. # # trail = Hike::Trail.new "~/Projects/hike" # trail.extensions.push ".rb" # trail.paths.push "lib", "test" # # trail.find "hike/trail" # # => "~/Projects/hike/lib/hike/trail.rb" # # trail.find "test_trail" # # => "~/Projects/hike/test/test_trail.rb" # # `find` accepts multiple fallback logical paths that returns the # first match. # # trail.find "hike", "hike/index" # # is equivalent to # # trail.find("hike") || trail.find("hike/index") # def find(*args) index.find(*args) end # `Trail#find_all` returns all matching paths including fallbacks and # shadowed matches. # # trail.find_all("hike", "hike/index").each { |path| warn path } # # `find_all` returns an `Enumerator`. This allows you to filter your # matches by any condition. # # trail.find_all("application").find do |path| # mime_type_for(path) == "text/css" # end # def find_all(*args, &block) cached.find_all(*args, &block) end # `Trail#cached` returns an `CachedTrail` object that has the same # interface as `Trail`. An `CachedTrail` is a cached `Trail` object that # does not update when the file system changes. If you are # confident that you are not making changes the paths you are # searching, `cached` will avoid excess system calls. # # cached = trail.cached # cached.find "hike/trail" # cached.find "test_trail" # def cached CachedTrail.new(root, paths, extensions, aliases) end # Deprecated alias for `cached`. alias_method :index, :cached private def normalize_extension(extension) if extension[/^\./] extension else ".#{extension}" end end end end hike-2.1.3/lib/hike/normalized_array.rb0000644000004100000410000000230313301515423020035 0ustar www-datawww-datamodule Hike # `NormalizedArray` is an internal abstract wrapper class that calls # a callback `normalize_element` anytime an element is added to the # Array. # # `Extensions` and `Paths` are subclasses of `NormalizedArray`. class NormalizedArray < Array def initialize super() end def []=(*args) value = args.pop if value.respond_to?(:to_ary) value = normalize_elements(value) else value = normalize_element(value) end super(*args.concat([value])) end def <<(element) super normalize_element(element) end def collect! super do |element| result = yield element normalize_element(result) end end alias_method :map!, :collect! def insert(index, *elements) super index, *normalize_elements(elements) end def push(*elements) super(*normalize_elements(elements)) end def replace(elements) super normalize_elements(elements) end def unshift(*elements) super(*normalize_elements(elements)) end def normalize_elements(elements) elements.map do |element| normalize_element(element) end end end end hike-2.1.3/lib/hike/paths.rb0000644000004100000410000000121213301515423015610 0ustar www-datawww-datarequire 'pathname' require 'hike/normalized_array' module Hike # `Paths` is an internal collection for tracking path strings. class Paths < NormalizedArray def initialize(root = ".") @root = Pathname.new(root) super() end # Relative paths added to this array are expanded relative to `@root`. # # paths = Paths.new("/usr/local") # paths << "tmp" # paths << "/tmp" # # paths # # => ["/usr/local/tmp", "/tmp"] # def normalize_element(path) path = Pathname.new(path) path = @root.join(path) if path.relative? path.expand_path.to_s end end end hike-2.1.3/lib/hike/cached_trail.rb0000644000004100000410000001357713301515423017114 0ustar www-datawww-datamodule Hike # `CachedTrail` 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 `CachedTrail` object. class CachedTrail include FileUtils # `CachedTrail#paths` is an immutable `Paths` collection. attr_reader :paths # `CachedTrail#extensions` is an immutable `Extensions` collection. attr_reader :extensions # `CachedTrail#aliases` is an immutable `Hash` mapping an extension to # an `Array` of aliases. attr_reader :aliases # `CachedTrail.new` is an internal method. Instead of constructing it # directly, create a `Trail` and call `Trail#CachedTrail`. def initialize(root, paths, extensions, aliases) @root = root.to_s # 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 # Create a reverse mapping from extension to possible aliases. @aliases = aliases.dup.freeze @reverse_aliases = @aliases.inject({}) { |h, (k, a)| (h[a] ||= []) << k; h } @stats = Hash.new { |h, k| h[k] = FileUtils.stat(k) } @entries = Hash.new { |h, k| h[k] = FileUtils.entries(k) } @patterns = Hash.new { |h, k| h[k] = pattern_for(k) } end # `CachedTrail#root` returns root path as a `String`. This attribute is immutable. attr_reader :root # `CachedTrail#cached` returns `self` to be compatable with the `Trail` interface. def cached self end # Deprecated alias for `cached`. alias_method :index, :cached # The real implementation of `find`. `Trail#find` generates a one # time cache and delegates here. # # See `Trail#find` for usage. def find(*logical_paths) find_all(*logical_paths).first end # The real implementation of `find_all`. `Trail#find_all` generates a one # time index and delegates here. # # See `Trail#find_all` for usage. def find_all(*logical_paths, &block) return to_enum(__method__, *logical_paths) unless block_given? options = extract_options!(logical_paths) base_path = (options[:base_path] || root).to_s logical_paths.each do |logical_path| logical_path = 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 end # A cached version of `Dir.entries` that filters out `.` files and # `~` swap files. Returns an empty `Array` if the directory does # not exist. def entries(path) @entries[path] end # A cached version of `File.stat`. Returns nil if the file does # not exist. def stat(path) @stats[path] end protected def extract_options!(arguments) arguments.last.is_a?(Hash) ? arguments.pop.dup : {} end def relative?(path) path =~ /^\.\.?\// end # Finds logical path across all `paths` def find_in_paths(logical_path, &block) dirname, basename = File.split(logical_path) @paths.each do |base_path| match(File.expand_path(dirname, base_path), basename, &block) end end # Finds relative logical path, `../test/test_trail`. Requires a # `base_path` for reference. def find_in_base_path(logical_path, base_path, &block) candidate = File.expand_path(logical_path, base_path) dirname, basename = File.split(candidate) match(dirname, basename, &block) if paths_contain?(dirname) end # Checks if the path is actually on the file system and performs # any syscalls if necessary. def match(dirname, basename) # Potential `entries` syscall matches = @entries[dirname] pattern = @patterns[basename] matches = matches.select { |m| m =~ pattern } sort_matches(matches, basename).each do |path| filename = File.join(dirname, path) # Potential `stat` syscall stat = @stats[filename] # Exclude directories if stat && stat.file? yield filename end end end # Returns true if `dirname` is a subdirectory of any of the `paths` def paths_contain?(dirname) paths.any? { |path| dirname[0, path.length] == path } end # Returns a `Regexp` that matches the allowed extensions. # # pattern_for("index.html") #=> /^index(.html|.htm)(.builder|.erb)*$/ def pattern_for(basename) extname = File.extname(basename) aliases = @reverse_aliases[extname] if aliases basename = File.basename(basename, extname) aliases = [extname] + aliases aliases_pattern = aliases.map { |e| Regexp.escape(e) }.join("|") basename_re = Regexp.escape(basename) + "(?:#{aliases_pattern})" else basename_re = Regexp.escape(basename) end extension_pattern = extensions.map { |e| Regexp.escape(e) }.join("|") /^#{basename_re}(?:#{extension_pattern})*$/ end # Sorts candidate matches by their extension # priority. Extensions in the front of the `extensions` carry # more weight. def sort_matches(matches, basename) extname = File.extname(basename) aliases = @reverse_aliases[extname] || [] matches.sort_by do |match| extnames = match.sub(basename, '').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 end end hike-2.1.3/lib/hike/extensions.rb0000644000004100000410000000077313301515423016703 0ustar www-datawww-datarequire 'hike/normalized_array' module Hike # `Extensions` is an internal collection for tracking extension names. class Extensions < NormalizedArray # Extensions added to this array are normalized with a leading # `.`. # # extensions << "js" # extensions << ".css" # # extensions # # => [".js", ".css"] # def normalize_element(extension) if extension[/^\./] extension else ".#{extension}" end end end end hike-2.1.3/lib/hike.rb0000644000004100000410000000047413301515423014502 0ustar www-datawww-datamodule Hike VERSION = "2.1.3" autoload :CachedTrail, "hike/cached_trail" autoload :Extensions, "hike/extensions" autoload :FileUtils, "hike/fileutils" autoload :NormalizedArray, "hike/normalized_array" autoload :Paths, "hike/paths" autoload :Trail, "hike/trail" end