epath 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +2 -2
- data/lib/epath.rb +1 -0
- data/lib/epath/compatibility.rb +60 -0
- data/lib/epath/dir.rb +8 -4
- data/lib/epath/file.rb +21 -4
- data/lib/epath/identity.rb +99 -5
- data/lib/epath/implementation.rb +72 -225
- data/lib/epath/parts.rb +1 -3
- data/lib/epath/predicates.rb +3 -7
- data/lib/epath/require_tree.rb +36 -16
- data/lib/epath/version.rb +1 -1
- metadata +52 -34
- data/lib/epath/file_dir.rb +0 -12
    
        data/README.md
    CHANGED
    
    | @@ -164,10 +164,10 @@ String (not using a path library), Pathname, or another library. | |
| 164 164 | 
             
            To this intend, [`Path + config`](http://rubydoc.info/github/eregon/epath/master/Path#%2B-class_method) allows to configure the behavior of `Path#+`.
         | 
| 165 165 |  | 
| 166 166 | 
             
            Coming from String, one should use `Path + :string`, and run ruby with the verbose option (`-w`),
         | 
| 167 | 
            -
            which will show  | 
| 167 | 
            +
            which will show where `+` is used as String concatenation.
         | 
| 168 168 |  | 
| 169 169 | 
             
            Coming from a path library using `+` as #join, one should just use the default (`Path + :warning`),
         | 
| 170 | 
            -
            which will show  | 
| 170 | 
            +
            which will show where `+` is used.
         | 
| 171 171 |  | 
| 172 172 | 
             
            ## Status
         | 
| 173 173 |  | 
    
        data/lib/epath.rb
    CHANGED
    
    | @@ -79,6 +79,7 @@ class Path | |
| 79 79 |  | 
| 80 80 | 
             
              # Whether +self+ is inside +ancestor+, such that +ancestor+ is an ancestor of +self+.
         | 
| 81 81 | 
             
              # This is pure String manipulation. Paths should be absolute.
         | 
| 82 | 
            +
              # +self+ is considered to be inside itself.
         | 
| 82 83 | 
             
              def inside? ancestor
         | 
| 83 84 | 
             
                @path == ancestor.to_s or @path.start_with?("#{ancestor}/")
         | 
| 84 85 | 
             
              end
         | 
| @@ -0,0 +1,60 @@ | |
| 1 | 
            +
            class Path
         | 
| 2 | 
            +
              private
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              if File.respond_to?(:realpath) and File.respond_to?(:realdirpath)
         | 
| 5 | 
            +
                def real_path_internal(strict = false, basedir = nil)
         | 
| 6 | 
            +
                  strict ? File.realpath(@path, basedir) : File.realdirpath(@path, basedir)
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
              else
         | 
| 9 | 
            +
                def realpath_rec(prefix, unresolved, h, strict, last = true)
         | 
| 10 | 
            +
                  resolved = []
         | 
| 11 | 
            +
                  until unresolved.empty?
         | 
| 12 | 
            +
                    n = unresolved.shift
         | 
| 13 | 
            +
                    if n == '..'
         | 
| 14 | 
            +
                      resolved.pop
         | 
| 15 | 
            +
                    else
         | 
| 16 | 
            +
                      path = prepend_prefix(prefix, resolved + [n])
         | 
| 17 | 
            +
                      if h.include? path
         | 
| 18 | 
            +
                        if h[path] == :resolving
         | 
| 19 | 
            +
                          raise Errno::ELOOP.new(path)
         | 
| 20 | 
            +
                        else
         | 
| 21 | 
            +
                          prefix, *resolved = h[path]
         | 
| 22 | 
            +
                        end
         | 
| 23 | 
            +
                      else
         | 
| 24 | 
            +
                        begin
         | 
| 25 | 
            +
                          s = File.lstat(path)
         | 
| 26 | 
            +
                        rescue Errno::ENOENT => e
         | 
| 27 | 
            +
                          raise e if strict || !last || !unresolved.empty?
         | 
| 28 | 
            +
                          resolved << n
         | 
| 29 | 
            +
                          break
         | 
| 30 | 
            +
                        end
         | 
| 31 | 
            +
                        if s.symlink?
         | 
| 32 | 
            +
                          h[path] = :resolving
         | 
| 33 | 
            +
                          link_prefix, link_names = split_names(File.readlink(path))
         | 
| 34 | 
            +
                          if link_prefix == '' # if link is relative
         | 
| 35 | 
            +
                            link_prefix, link_names = prefix, resolved.concat(link_names)
         | 
| 36 | 
            +
                          end
         | 
| 37 | 
            +
                          prefix, *resolved = h[path] = realpath_rec(link_prefix, link_names, h, strict, unresolved.empty?)
         | 
| 38 | 
            +
                        else
         | 
| 39 | 
            +
                          resolved << n
         | 
| 40 | 
            +
                          h[path] = [prefix, *resolved]
         | 
| 41 | 
            +
                        end
         | 
| 42 | 
            +
                      end
         | 
| 43 | 
            +
                    end
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
                  return prefix, *resolved
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                def real_path_internal(strict = false, basedir = nil)
         | 
| 49 | 
            +
                  path = @path
         | 
| 50 | 
            +
                  path = File.join(basedir, path) if basedir and relative?
         | 
| 51 | 
            +
                  prefix, names = split_names(path)
         | 
| 52 | 
            +
                  if prefix == ''
         | 
| 53 | 
            +
                    prefix, names2 = split_names(Dir.pwd)
         | 
| 54 | 
            +
                    names = names2.concat(names)
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
                  prefix, *names = realpath_rec(prefix, names, {}, strict)
         | 
| 57 | 
            +
                  prepend_prefix(prefix, names)
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
              end
         | 
| 60 | 
            +
            end
         | 
    
        data/lib/epath/dir.rb
    CHANGED
    
    | @@ -4,11 +4,11 @@ class Path | |
| 4 4 |  | 
| 5 5 | 
             
                # Returns or yields Path objects. See +Dir.glob+.
         | 
| 6 6 | 
             
                # @yieldparam [Path] path
         | 
| 7 | 
            -
                def glob( | 
| 7 | 
            +
                def glob(pattern, flags = 0)
         | 
| 8 8 | 
             
                  if block_given?
         | 
| 9 | 
            -
                    Dir.glob( | 
| 9 | 
            +
                    Dir.glob(pattern, flags) { |f| yield new(f) }
         | 
| 10 10 | 
             
                  else
         | 
| 11 | 
            -
                    Dir.glob( | 
| 11 | 
            +
                    Dir.glob(pattern, flags).map(&Path)
         | 
| 12 12 | 
             
                  end
         | 
| 13 13 | 
             
                end
         | 
| 14 14 |  | 
| @@ -58,7 +58,11 @@ class Path | |
| 58 58 | 
             
              # Returns or yields Path objects. See +Dir.glob+.
         | 
| 59 59 | 
             
              # @yieldparam [Path] path
         | 
| 60 60 | 
             
              def glob(pattern, flags = 0)
         | 
| 61 | 
            -
                 | 
| 61 | 
            +
                if block_given?
         | 
| 62 | 
            +
                  Dir.glob(join(pattern), flags) { |f| yield Path.new(f) }
         | 
| 63 | 
            +
                else
         | 
| 64 | 
            +
                  Dir.glob(join(pattern), flags).map(&Path)
         | 
| 65 | 
            +
                end
         | 
| 62 66 | 
             
              end
         | 
| 63 67 |  | 
| 64 68 | 
             
              # Return the entries (files and subdirectories) in the directory.
         | 
    
        data/lib/epath/file.rb
    CHANGED
    
    | @@ -18,10 +18,14 @@ class Path | |
| 18 18 | 
             
              end
         | 
| 19 19 |  | 
| 20 20 | 
             
              # Changes permissions of +path+. See +File.chmod+.
         | 
| 21 | 
            -
              def chmod(mode) | 
| 21 | 
            +
              def chmod(mode)
         | 
| 22 | 
            +
                File.chmod(mode, @path)
         | 
| 23 | 
            +
              end
         | 
| 22 24 |  | 
| 23 25 | 
             
              # Changes permissions of +path+, not following symlink. See +File.lchmod+.
         | 
| 24 | 
            -
              def lchmod(mode) | 
| 26 | 
            +
              def lchmod(mode)
         | 
| 27 | 
            +
                File.lchmod(mode, @path)
         | 
| 28 | 
            +
              end
         | 
| 25 29 |  | 
| 26 30 | 
             
              # Changes the owner and group of the file. See +File.chown+.
         | 
| 27 31 | 
             
              def chown(owner, group)
         | 
| @@ -84,10 +88,23 @@ class Path | |
| 84 88 | 
             
              end
         | 
| 85 89 |  | 
| 86 90 | 
             
              # Truncates the file to +length+ bytes. See +File.truncate+.
         | 
| 87 | 
            -
              def truncate(length) | 
| 91 | 
            +
              def truncate(length)
         | 
| 92 | 
            +
                File.truncate(@path, length)
         | 
| 93 | 
            +
              end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
              # Removes a file using +File.unlink+.
         | 
| 96 | 
            +
              # This is incompatible with Pathname#unlink,
         | 
| 97 | 
            +
              # which can also remove directories.
         | 
| 98 | 
            +
              # Use {#rmdir} or {#rm_r} for directories.
         | 
| 99 | 
            +
              def unlink
         | 
| 100 | 
            +
                File.unlink @path
         | 
| 101 | 
            +
              end
         | 
| 102 | 
            +
              alias :delete :unlink
         | 
| 88 103 |  | 
| 89 104 | 
             
              # Updates the access and modification times. See +File.utime+.
         | 
| 90 | 
            -
              def utime(atime, mtime) | 
| 105 | 
            +
              def utime(atime, mtime)
         | 
| 106 | 
            +
                File.utime(atime, mtime, @path)
         | 
| 107 | 
            +
              end
         | 
| 91 108 |  | 
| 92 109 | 
             
              # Expands +path+, making it absolute.
         | 
| 93 110 | 
             
              # If the path is relative, it is expanded with the current working directory,
         | 
    
        data/lib/epath/identity.rb
    CHANGED
    
    | @@ -4,8 +4,8 @@ class Path | |
| 4 4 |  | 
| 5 5 | 
             
                # Creates a new Path. See {#initialize}.
         | 
| 6 6 | 
             
                def new(*args)
         | 
| 7 | 
            -
                  if args.size == 1 and Path === args | 
| 8 | 
            -
                    args | 
| 7 | 
            +
                  if args.size == 1 and Path === args.first
         | 
| 8 | 
            +
                    args.first
         | 
| 9 9 | 
             
                  else
         | 
| 10 10 | 
             
                    super(*args)
         | 
| 11 11 | 
             
                  end
         | 
| @@ -18,10 +18,65 @@ class Path | |
| 18 18 | 
             
                def to_proc
         | 
| 19 19 | 
             
                  lambda { |path| new(path) }
         | 
| 20 20 | 
             
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                # Whether +object+ looks like a path.
         | 
| 23 | 
            +
                # The current test checks if the object responds to
         | 
| 24 | 
            +
                # #to_path, #path or #to_str.
         | 
| 25 | 
            +
                def like? object
         | 
| 26 | 
            +
                  [:to_path, :path, :to_str].any? { |meth| object.respond_to? meth }
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                # A matcher responding to #===. Useful for case clauses, grep, etc.
         | 
| 30 | 
            +
                # See {Path.like?}.
         | 
| 31 | 
            +
                #
         | 
| 32 | 
            +
                #   case obj
         | 
| 33 | 
            +
                #   when Path.like then Path(obj)
         | 
| 34 | 
            +
                #   # ...
         | 
| 35 | 
            +
                #   end
         | 
| 36 | 
            +
                def like
         | 
| 37 | 
            +
                  @like ||= begin
         | 
| 38 | 
            +
                    matcher = Object.new
         | 
| 39 | 
            +
                    def matcher.===(object)
         | 
| 40 | 
            +
                      Path.like?(object)
         | 
| 41 | 
            +
                    end
         | 
| 42 | 
            +
                    matcher
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                end
         | 
| 21 45 | 
             
              end
         | 
| 22 46 |  | 
| 23 47 | 
             
              # @!group Identity
         | 
| 24 48 |  | 
| 49 | 
            +
              # Creates a new Path.
         | 
| 50 | 
            +
              # If multiple arguments are given, they are joined with File.join.
         | 
| 51 | 
            +
              # The path will have File::ALT_SEPARATOR replaced with '/' and
         | 
| 52 | 
            +
              # if it begins with a '~', it will be expanded (using File.expand_path).
         | 
| 53 | 
            +
              # Accepts an Array of Strings, a Tempfile, anything that respond to #path,
         | 
| 54 | 
            +
              # #to_path or #to_str with a String and defaults to calling #to_s.
         | 
| 55 | 
            +
              #
         | 
| 56 | 
            +
              # @param parts [Array<String>, Tempfile, #to_path, #path, #to_str, #to_s] the path-like object(s)
         | 
| 57 | 
            +
              def initialize(*parts)
         | 
| 58 | 
            +
                path = parts.size > 1 ? File.join(*parts) : parts.first
         | 
| 59 | 
            +
                @path = case path
         | 
| 60 | 
            +
                when Tempfile
         | 
| 61 | 
            +
                  @_tmpfile = path # We would not want it to be GC'd
         | 
| 62 | 
            +
                  path.path.dup
         | 
| 63 | 
            +
                when String
         | 
| 64 | 
            +
                  path.dup
         | 
| 65 | 
            +
                else
         | 
| 66 | 
            +
                  if path.respond_to? :to_path and String === path.to_path
         | 
| 67 | 
            +
                    path.to_path.dup
         | 
| 68 | 
            +
                  elsif path.respond_to? :path and String === path.path
         | 
| 69 | 
            +
                    path.path.dup
         | 
| 70 | 
            +
                  elsif path.respond_to? :to_str and String === path.to_str
         | 
| 71 | 
            +
                    path.to_str.dup
         | 
| 72 | 
            +
                  else
         | 
| 73 | 
            +
                    path.to_s.dup
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
                end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                init
         | 
| 78 | 
            +
              end
         | 
| 79 | 
            +
             | 
| 25 80 | 
             
              # Returns the +path+ as a String.
         | 
| 26 81 | 
             
              # {#path} is implemented for better readability (+file.path+ instead of +file.to_s+) and as an accessor.
         | 
| 27 82 | 
             
              # {#to_path} is implemented so Path objects are usable with +open+, etc.
         | 
| @@ -59,11 +114,50 @@ class Path | |
| 59 114 | 
             
              def inspect
         | 
| 60 115 | 
             
                "#<Path #{@path}>"
         | 
| 61 116 | 
             
              end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
              # YAML loading.
         | 
| 119 | 
            +
              def yaml_initialize(tag, ivars)
         | 
| 120 | 
            +
                @path = ivars['path']
         | 
| 121 | 
            +
                init
         | 
| 122 | 
            +
              end
         | 
| 123 | 
            +
             | 
| 124 | 
            +
              # Psych loading.
         | 
| 125 | 
            +
              def init_with(coder)
         | 
| 126 | 
            +
                @path = coder['path']
         | 
| 127 | 
            +
                init
         | 
| 128 | 
            +
              end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
              # JSON dumping.
         | 
| 131 | 
            +
              def to_json(*args)
         | 
| 132 | 
            +
                {
         | 
| 133 | 
            +
                  'json_class' => 'Path',
         | 
| 134 | 
            +
                  'data'       => @path
         | 
| 135 | 
            +
                }.to_json(*args)
         | 
| 136 | 
            +
              end
         | 
| 137 | 
            +
             | 
| 138 | 
            +
              # JSON loading.
         | 
| 139 | 
            +
              def self.json_create json
         | 
| 140 | 
            +
                new json['data']
         | 
| 141 | 
            +
              end
         | 
| 142 | 
            +
             | 
| 143 | 
            +
              # Marshal dumping.
         | 
| 144 | 
            +
              def marshal_dump
         | 
| 145 | 
            +
                @path
         | 
| 146 | 
            +
              end
         | 
| 147 | 
            +
             | 
| 148 | 
            +
              # Marshal loading.
         | 
| 149 | 
            +
              def marshal_load path
         | 
| 150 | 
            +
                @path = path
         | 
| 151 | 
            +
                init
         | 
| 152 | 
            +
              end
         | 
| 62 153 | 
             
            end
         | 
| 63 154 |  | 
| 64 155 | 
             
            unless defined? NO_EPATH_GLOBAL_FUNCTION
         | 
| 65 | 
            -
               | 
| 66 | 
            -
             | 
| 67 | 
            -
                Path | 
| 156 | 
            +
              module Kernel
         | 
| 157 | 
            +
                # A shorthand method to create a {Path}. Same as {Path.new}.
         | 
| 158 | 
            +
                def Path(*args)
         | 
| 159 | 
            +
                  Path.new(*args)
         | 
| 160 | 
            +
                end
         | 
| 161 | 
            +
                private :Path
         | 
| 68 162 | 
             
              end
         | 
| 69 163 | 
             
            end
         | 
    
        data/lib/epath/implementation.rb
    CHANGED
    
    | @@ -8,61 +8,6 @@ class Path | |
| 8 8 | 
             
                lambda { |a,b| a == b }
         | 
| 9 9 | 
             
              end
         | 
| 10 10 |  | 
| 11 | 
            -
              # Creates a new Path.
         | 
| 12 | 
            -
              # If multiple arguments are given, they are joined with File.join.
         | 
| 13 | 
            -
              # The path will have File::ALT_SEPARATOR replaced with '/' and
         | 
| 14 | 
            -
              # if it begins with a '~', it will be expanded (using File.expand_path).
         | 
| 15 | 
            -
              def initialize(*parts)
         | 
| 16 | 
            -
                path = parts.size > 1 ? File.join(*parts) : parts.first
         | 
| 17 | 
            -
                @path = case path
         | 
| 18 | 
            -
                when Tempfile
         | 
| 19 | 
            -
                  @_tmpfile = path # We would not want it to be GC'd
         | 
| 20 | 
            -
                  path.path.dup
         | 
| 21 | 
            -
                when String
         | 
| 22 | 
            -
                  path.dup
         | 
| 23 | 
            -
                else
         | 
| 24 | 
            -
                  path.to_s.dup
         | 
| 25 | 
            -
                end
         | 
| 26 | 
            -
             | 
| 27 | 
            -
                init
         | 
| 28 | 
            -
              end
         | 
| 29 | 
            -
             | 
| 30 | 
            -
              # YAML loading.
         | 
| 31 | 
            -
              def yaml_initialize(tag, ivars)
         | 
| 32 | 
            -
                @path = ivars['path']
         | 
| 33 | 
            -
                init
         | 
| 34 | 
            -
              end
         | 
| 35 | 
            -
             | 
| 36 | 
            -
              # Psych loading.
         | 
| 37 | 
            -
              def init_with(coder)
         | 
| 38 | 
            -
                @path = coder['path']
         | 
| 39 | 
            -
                init
         | 
| 40 | 
            -
              end
         | 
| 41 | 
            -
             | 
| 42 | 
            -
              # JSON dumping.
         | 
| 43 | 
            -
              def to_json(*args)
         | 
| 44 | 
            -
                {
         | 
| 45 | 
            -
                  'json_class' => 'Path',
         | 
| 46 | 
            -
                  'data'       => @path
         | 
| 47 | 
            -
                }.to_json(*args)
         | 
| 48 | 
            -
              end
         | 
| 49 | 
            -
             | 
| 50 | 
            -
              # JSON loading.
         | 
| 51 | 
            -
              def self.json_create json
         | 
| 52 | 
            -
                new json['data']
         | 
| 53 | 
            -
              end
         | 
| 54 | 
            -
             | 
| 55 | 
            -
              # Marshal dumping.
         | 
| 56 | 
            -
              def marshal_dump
         | 
| 57 | 
            -
                @path
         | 
| 58 | 
            -
              end
         | 
| 59 | 
            -
             | 
| 60 | 
            -
              # Marshal loading.
         | 
| 61 | 
            -
              def marshal_load path
         | 
| 62 | 
            -
                @path = path
         | 
| 63 | 
            -
                init
         | 
| 64 | 
            -
              end
         | 
| 65 | 
            -
             | 
| 66 11 | 
             
              # Returns a cleaned version of +self+ with consecutive slashes and useless dots removed.
         | 
| 67 12 | 
             
              # The filesystem is not accessed.
         | 
| 68 13 | 
             
              #
         | 
| @@ -143,16 +88,13 @@ class Path | |
| 143 88 | 
             
              #   path0.join(path1, ..., pathN)
         | 
| 144 89 | 
             
              #   # is the same as
         | 
| 145 90 | 
             
              #   path0 / path1 / ... / pathN
         | 
| 146 | 
            -
              def join(* | 
| 147 | 
            -
                 | 
| 148 | 
            -
                 | 
| 149 | 
            -
             | 
| 150 | 
            -
                args.reverse_each { |arg|
         | 
| 151 | 
            -
                  arg = Path.new(arg)
         | 
| 152 | 
            -
                  result = arg / result
         | 
| 91 | 
            +
              def join(*paths)
         | 
| 92 | 
            +
                result = nil
         | 
| 93 | 
            +
                paths.reverse_each { |path|
         | 
| 94 | 
            +
                  result = Path.new(path) / result
         | 
| 153 95 | 
             
                  return result if result.absolute?
         | 
| 154 96 | 
             
                }
         | 
| 155 | 
            -
                result
         | 
| 97 | 
            +
                self / result
         | 
| 156 98 | 
             
              end
         | 
| 157 99 |  | 
| 158 100 | 
             
              # #relative_path_from returns a relative path from the argument to the
         | 
| @@ -163,37 +105,23 @@ class Path | |
| 163 105 | 
             
              #
         | 
| 164 106 | 
             
              # ArgumentError is raised when it cannot find a relative path.
         | 
| 165 107 | 
             
              def relative_path_from(base_directory)
         | 
| 166 | 
            -
                 | 
| 167 | 
            -
                 | 
| 168 | 
            -
                dest_prefix =  | 
| 169 | 
            -
                 | 
| 170 | 
            -
             | 
| 171 | 
            -
                  dest_prefix, basename = r
         | 
| 172 | 
            -
                  dest_names.unshift basename if basename != '.'
         | 
| 173 | 
            -
                end
         | 
| 174 | 
            -
                base_prefix = base_directory
         | 
| 175 | 
            -
                base_names = []
         | 
| 176 | 
            -
                while r = chop_basename(base_prefix)
         | 
| 177 | 
            -
                  base_prefix, basename = r
         | 
| 178 | 
            -
                  base_names.unshift basename if basename != '.'
         | 
| 179 | 
            -
                end
         | 
| 108 | 
            +
                dest = clean.path
         | 
| 109 | 
            +
                base = Path.new(base_directory).clean.path
         | 
| 110 | 
            +
                dest_prefix, dest_names = split_names(dest)
         | 
| 111 | 
            +
                base_prefix, base_names = split_names(base)
         | 
| 112 | 
            +
             | 
| 180 113 | 
             
                unless SAME_PATHS[dest_prefix, base_prefix]
         | 
| 181 | 
            -
                  raise ArgumentError, "different prefix: #{ | 
| 114 | 
            +
                  raise ArgumentError, "different prefix: #{self.inspect} and #{base_directory.inspect}"
         | 
| 182 115 | 
             
                end
         | 
| 183 | 
            -
                 | 
| 116 | 
            +
                while d = dest_names.first and b = base_names.first and SAME_PATHS[d, b]
         | 
| 184 117 | 
             
                  dest_names.shift
         | 
| 185 118 | 
             
                  base_names.shift
         | 
| 186 119 | 
             
                end
         | 
| 187 | 
            -
                if base_names.include? '..'
         | 
| 188 | 
            -
             | 
| 189 | 
            -
                 | 
| 190 | 
            -
                 | 
| 191 | 
            -
                 | 
| 192 | 
            -
                if relpath_names.empty?
         | 
| 193 | 
            -
                  Path.new('.')
         | 
| 194 | 
            -
                else
         | 
| 195 | 
            -
                  Path.new(*relpath_names)
         | 
| 196 | 
            -
                end
         | 
| 120 | 
            +
                raise ArgumentError, "base_directory has ..: #{base_directory.inspect}" if base_names.include? '..'
         | 
| 121 | 
            +
                # the number of names left in base is the ones we have to climb
         | 
| 122 | 
            +
                names = base_names.fill('..').concat(dest_names)
         | 
| 123 | 
            +
                return Path.new('.') if names.empty?
         | 
| 124 | 
            +
                Path.new(*names)
         | 
| 197 125 | 
             
              end
         | 
| 198 126 | 
             
              alias :relative_to :relative_path_from
         | 
| 199 127 | 
             
              alias :% :relative_path_from
         | 
| @@ -243,41 +171,43 @@ class Path | |
| 243 171 | 
             
                end
         | 
| 244 172 | 
             
              end
         | 
| 245 173 |  | 
| 174 | 
            +
              def is_absolute?(path)
         | 
| 175 | 
            +
                path.start_with?('/') or (path =~ /\A[a-zA-Z]:\// and is_root?($&))
         | 
| 176 | 
            +
              end
         | 
| 177 | 
            +
             | 
| 178 | 
            +
              def is_root?(path)
         | 
| 179 | 
            +
                chop_basename(path) == nil and path.include?('/')
         | 
| 180 | 
            +
              end
         | 
| 181 | 
            +
             | 
| 246 182 | 
             
              # split_names(path) -> prefix, [name, ...]
         | 
| 247 183 | 
             
              def split_names(path)
         | 
| 248 184 | 
             
                names = []
         | 
| 249 185 | 
             
                while r = chop_basename(path)
         | 
| 250 186 | 
             
                  path, basename = r
         | 
| 251 | 
            -
                  names.unshift basename
         | 
| 187 | 
            +
                  names.unshift basename if basename != '.'
         | 
| 252 188 | 
             
                end
         | 
| 253 189 | 
             
                return path, names
         | 
| 254 190 | 
             
              end
         | 
| 255 191 |  | 
| 256 | 
            -
              def prepend_prefix(prefix,  | 
| 192 | 
            +
              def prepend_prefix(prefix, relnames)
         | 
| 193 | 
            +
                relpath = File.join(*relnames)
         | 
| 257 194 | 
             
                if relpath.empty?
         | 
| 258 195 | 
             
                  File.dirname(prefix)
         | 
| 259 196 | 
             
                elsif prefix.include? '/'
         | 
| 260 | 
            -
                   | 
| 197 | 
            +
                  # safe because File.dirname returns a new String
         | 
| 198 | 
            +
                  add_trailing_separator(File.dirname(prefix)) << relpath
         | 
| 261 199 | 
             
                else
         | 
| 262 200 | 
             
                  prefix + relpath
         | 
| 263 201 | 
             
                end
         | 
| 264 202 | 
             
              end
         | 
| 265 203 |  | 
| 266 204 | 
             
              def has_trailing_separator?(path)
         | 
| 267 | 
            -
                 | 
| 268 | 
            -
                  pre, basename = r
         | 
| 269 | 
            -
                  pre.length + basename.length < path.length
         | 
| 270 | 
            -
                else
         | 
| 271 | 
            -
                  false
         | 
| 272 | 
            -
                end
         | 
| 205 | 
            +
                !is_root?(path) and path.end_with?('/')
         | 
| 273 206 | 
             
              end
         | 
| 274 207 |  | 
| 275 | 
            -
              def add_trailing_separator(path)
         | 
| 276 | 
            -
                 | 
| 277 | 
            -
             | 
| 278 | 
            -
                else
         | 
| 279 | 
            -
                  path + '/'
         | 
| 280 | 
            -
                end
         | 
| 208 | 
            +
              def add_trailing_separator(path) # mutates path
         | 
| 209 | 
            +
                path << '/' unless path.end_with? '/'
         | 
| 210 | 
            +
                path
         | 
| 281 211 | 
             
              end
         | 
| 282 212 |  | 
| 283 213 | 
             
              def del_trailing_separator(path)
         | 
| @@ -291,51 +221,41 @@ class Path | |
| 291 221 | 
             
                end
         | 
| 292 222 | 
             
              end
         | 
| 293 223 |  | 
| 224 | 
            +
              # remove '..' segments since root's parent is root
         | 
| 225 | 
            +
              def remove_root_parents(prefix, names)
         | 
| 226 | 
            +
                names.shift while names.first == '..' if is_root?(prefix)
         | 
| 227 | 
            +
              end
         | 
| 228 | 
            +
             | 
| 294 229 | 
             
              # Clean the path simply by resolving and removing excess "." and ".." entries.
         | 
| 295 230 | 
             
              # Nothing more, nothing less.
         | 
| 296 231 | 
             
              def cleanpath_aggressive
         | 
| 297 | 
            -
                 | 
| 232 | 
            +
                pre = @path
         | 
| 298 233 | 
             
                names = []
         | 
| 299 | 
            -
                pre = path
         | 
| 300 234 | 
             
                while r = chop_basename(pre)
         | 
| 301 235 | 
             
                  pre, base = r
         | 
| 302 | 
            -
                   | 
| 303 | 
            -
             | 
| 304 | 
            -
                   | 
| 305 | 
            -
                     | 
| 236 | 
            +
                  if base == '.'
         | 
| 237 | 
            +
                    # do nothing, it can be ignored
         | 
| 238 | 
            +
                  elsif names.first == '..' and base != '..'
         | 
| 239 | 
            +
                    # base can be ignored as we go back to its parent
         | 
| 240 | 
            +
                    names.shift
         | 
| 306 241 | 
             
                  else
         | 
| 307 | 
            -
                     | 
| 308 | 
            -
                      names.shift
         | 
| 309 | 
            -
                    else
         | 
| 310 | 
            -
                      names.unshift base
         | 
| 311 | 
            -
                    end
         | 
| 242 | 
            +
                    names.unshift base
         | 
| 312 243 | 
             
                  end
         | 
| 313 244 | 
             
                end
         | 
| 314 | 
            -
                 | 
| 315 | 
            -
             | 
| 316 | 
            -
                end
         | 
| 317 | 
            -
                Path.new(prepend_prefix(pre, File.join(*names)))
         | 
| 245 | 
            +
                remove_root_parents(pre, names)
         | 
| 246 | 
            +
                Path.new(prepend_prefix(pre, names))
         | 
| 318 247 | 
             
              end
         | 
| 319 248 |  | 
| 320 249 | 
             
              def cleanpath_conservative
         | 
| 321 250 | 
             
                path = @path
         | 
| 322 | 
            -
                names =  | 
| 323 | 
            -
                pre  | 
| 324 | 
            -
                while r = chop_basename(pre)
         | 
| 325 | 
            -
                  pre, base = r
         | 
| 326 | 
            -
                  names.unshift base if base != '.'
         | 
| 327 | 
            -
                end
         | 
| 328 | 
            -
                if File.basename(pre).include? '/'
         | 
| 329 | 
            -
                  names.shift while names[0] == '..'
         | 
| 330 | 
            -
                end
         | 
| 251 | 
            +
                pre, names = split_names(path)
         | 
| 252 | 
            +
                remove_root_parents(pre, names)
         | 
| 331 253 | 
             
                if names.empty?
         | 
| 332 254 | 
             
                  Path.new(File.dirname(pre))
         | 
| 333 255 | 
             
                else
         | 
| 334 | 
            -
                  if names.last != '..'  | 
| 335 | 
            -
             | 
| 336 | 
            -
                   | 
| 337 | 
            -
                  result = prepend_prefix(pre, File.join(*names))
         | 
| 338 | 
            -
                  if /\A(?:\.|\.\.)\z/ !~ names.last && has_trailing_separator?(path)
         | 
| 256 | 
            +
                  names << '.' if names.last != '..' and File.basename(path) == '.'
         | 
| 257 | 
            +
                  result = prepend_prefix(pre, names)
         | 
| 258 | 
            +
                  if names.last != '.' and names.last != '..' and has_trailing_separator?(path)
         | 
| 339 259 | 
             
                    Path.new(add_trailing_separator(result))
         | 
| 340 260 | 
             
                  else
         | 
| 341 261 | 
             
                    Path.new(result)
         | 
| @@ -343,104 +263,31 @@ class Path | |
| 343 263 | 
             
                end
         | 
| 344 264 | 
             
              end
         | 
| 345 265 |  | 
| 346 | 
            -
               | 
| 347 | 
            -
                 | 
| 348 | 
            -
             | 
| 349 | 
            -
                end
         | 
| 350 | 
            -
              else
         | 
| 351 | 
            -
                def realpath_rec(prefix, unresolved, h, strict, last = true)
         | 
| 352 | 
            -
                  resolved = []
         | 
| 353 | 
            -
                  until unresolved.empty?
         | 
| 354 | 
            -
                    n = unresolved.shift
         | 
| 355 | 
            -
                    if n == '.'
         | 
| 356 | 
            -
                      next
         | 
| 357 | 
            -
                    elsif n == '..'
         | 
| 358 | 
            -
                      resolved.pop
         | 
| 359 | 
            -
                    else
         | 
| 360 | 
            -
                      path = prepend_prefix(prefix, File.join(*(resolved + [n])))
         | 
| 361 | 
            -
                      if h.include? path
         | 
| 362 | 
            -
                        if h[path] == :resolving
         | 
| 363 | 
            -
                          raise Errno::ELOOP.new(path)
         | 
| 364 | 
            -
                        else
         | 
| 365 | 
            -
                          prefix, *resolved = h[path]
         | 
| 366 | 
            -
                        end
         | 
| 367 | 
            -
                      else
         | 
| 368 | 
            -
                        begin
         | 
| 369 | 
            -
                          s = File.lstat(path)
         | 
| 370 | 
            -
                        rescue Errno::ENOENT => e
         | 
| 371 | 
            -
                          raise e if strict || !last || !unresolved.empty?
         | 
| 372 | 
            -
                          resolved << n
         | 
| 373 | 
            -
                          break
         | 
| 374 | 
            -
                        end
         | 
| 375 | 
            -
                        if s.symlink?
         | 
| 376 | 
            -
                          h[path] = :resolving
         | 
| 377 | 
            -
                          link_prefix, link_names = split_names(File.readlink(path))
         | 
| 378 | 
            -
                          if link_prefix == ''
         | 
| 379 | 
            -
                            prefix, *resolved = h[path] = realpath_rec(prefix, resolved + link_names, h, strict, unresolved.empty?)
         | 
| 380 | 
            -
                          else
         | 
| 381 | 
            -
                            prefix, *resolved = h[path] = realpath_rec(link_prefix, link_names, h, strict, unresolved.empty?)
         | 
| 382 | 
            -
                          end
         | 
| 383 | 
            -
                        else
         | 
| 384 | 
            -
                          resolved << n
         | 
| 385 | 
            -
                          h[path] = [prefix, *resolved]
         | 
| 386 | 
            -
                        end
         | 
| 387 | 
            -
                      end
         | 
| 388 | 
            -
                    end
         | 
| 389 | 
            -
                  end
         | 
| 390 | 
            -
                  return prefix, *resolved
         | 
| 391 | 
            -
                end
         | 
| 266 | 
            +
              def plus(prefix, rel)
         | 
| 267 | 
            +
                return rel if is_absolute?(rel)
         | 
| 268 | 
            +
                _, names = split_names(rel)
         | 
| 392 269 |  | 
| 393 | 
            -
                 | 
| 394 | 
            -
                   | 
| 395 | 
            -
                   | 
| 396 | 
            -
                  prefix,  | 
| 397 | 
            -
                  if  | 
| 398 | 
            -
                    prefix, names2 = split_names(Dir.pwd)
         | 
| 399 | 
            -
                    names = names2 + names
         | 
| 400 | 
            -
                  end
         | 
| 401 | 
            -
                  prefix, *names = realpath_rec(prefix, names, {}, strict)
         | 
| 402 | 
            -
                  prepend_prefix(prefix, File.join(*names))
         | 
| 403 | 
            -
                end
         | 
| 404 | 
            -
              end
         | 
| 270 | 
            +
                loop do
         | 
| 271 | 
            +
                  # break if that was the last segment
         | 
| 272 | 
            +
                  break unless r = chop_basename(prefix)
         | 
| 273 | 
            +
                  prefix, name = r
         | 
| 274 | 
            +
                  next if name == '.'
         | 
| 405 275 |  | 
| 406 | 
            -
             | 
| 407 | 
            -
             | 
| 408 | 
            -
             | 
| 409 | 
            -
                basename_list2 = []
         | 
| 410 | 
            -
                while r2 = chop_basename(prefix2)
         | 
| 411 | 
            -
                  prefix2, basename2 = r2
         | 
| 412 | 
            -
                  index_list2.unshift prefix2.length
         | 
| 413 | 
            -
                  basename_list2.unshift basename2
         | 
| 414 | 
            -
                end
         | 
| 415 | 
            -
                return path2 if prefix2 != ''
         | 
| 416 | 
            -
                prefix1 = path1
         | 
| 417 | 
            -
                while true
         | 
| 418 | 
            -
                  while !basename_list2.empty? && basename_list2.first == '.'
         | 
| 419 | 
            -
                    index_list2.shift
         | 
| 420 | 
            -
                    basename_list2.shift
         | 
| 421 | 
            -
                  end
         | 
| 422 | 
            -
                  break unless r1 = chop_basename(prefix1)
         | 
| 423 | 
            -
                  prefix1, basename1 = r1
         | 
| 424 | 
            -
                  next if basename1 == '.'
         | 
| 425 | 
            -
                  if basename1 == '..' || basename_list2.empty? || basename_list2.first != '..'
         | 
| 426 | 
            -
                    prefix1 = prefix1 + basename1
         | 
| 276 | 
            +
                  # break if we can't resolve anymore
         | 
| 277 | 
            +
                  if name == '..' or names.first != '..'
         | 
| 278 | 
            +
                    prefix << name
         | 
| 427 279 | 
             
                    break
         | 
| 428 280 | 
             
                  end
         | 
| 429 | 
            -
                   | 
| 430 | 
            -
                  basename_list2.shift
         | 
| 281 | 
            +
                  names.shift
         | 
| 431 282 | 
             
                end
         | 
| 432 | 
            -
             | 
| 433 | 
            -
                 | 
| 434 | 
            -
             | 
| 435 | 
            -
             | 
| 436 | 
            -
             | 
| 437 | 
            -
                  end
         | 
| 438 | 
            -
                end
         | 
| 439 | 
            -
                if !basename_list2.empty?
         | 
| 440 | 
            -
                  suffix2 = path2[index_list2.first..-1]
         | 
| 441 | 
            -
                  r1 ? File.join(prefix1, suffix2) : prefix1 + suffix2
         | 
| 283 | 
            +
             | 
| 284 | 
            +
                remove_root_parents(prefix, names)
         | 
| 285 | 
            +
                has_prefix = chop_basename(prefix)
         | 
| 286 | 
            +
                if names.empty?
         | 
| 287 | 
            +
                  has_prefix ? prefix : File.dirname(prefix)
         | 
| 442 288 | 
             
                else
         | 
| 443 | 
            -
                   | 
| 289 | 
            +
                  suffix = File.join(*names)
         | 
| 290 | 
            +
                  has_prefix ? File.join(prefix, suffix) : prefix + suffix
         | 
| 444 291 | 
             
                end
         | 
| 445 292 | 
             
              end
         | 
| 446 293 | 
             
            end
         | 
    
        data/lib/epath/parts.rb
    CHANGED
    
    
    
        data/lib/epath/predicates.rb
    CHANGED
    
    | @@ -3,16 +3,12 @@ class Path | |
| 3 3 |  | 
| 4 4 | 
             
              # Whether a path is absolute.
         | 
| 5 5 | 
             
              def absolute?
         | 
| 6 | 
            -
                 | 
| 6 | 
            +
                is_absolute?(@path)
         | 
| 7 7 | 
             
              end
         | 
| 8 8 |  | 
| 9 9 | 
             
              # Whether a path is relative.
         | 
| 10 10 | 
             
              def relative?
         | 
| 11 | 
            -
                 | 
| 12 | 
            -
                while r = chop_basename(path)
         | 
| 13 | 
            -
                  path, = r
         | 
| 14 | 
            -
                end
         | 
| 15 | 
            -
                path == ''
         | 
| 11 | 
            +
                not absolute?
         | 
| 16 12 | 
             
              end
         | 
| 17 13 |  | 
| 18 14 | 
             
              # #root? is a predicate for root directories. I.e. it returns +true+ if the
         | 
| @@ -21,7 +17,7 @@ class Path | |
| 21 17 | 
             
              # It doesn't access actual filesystem. So it may return +false+ for some
         | 
| 22 18 | 
             
              # paths which points to roots such as +/usr/..+.
         | 
| 23 19 | 
             
              def root?
         | 
| 24 | 
            -
                 | 
| 20 | 
            +
                is_root?(@path)
         | 
| 25 21 | 
             
              end
         | 
| 26 22 |  | 
| 27 23 | 
             
              # #mountpoint? returns +true+ if +self+ points to a mountpoint.
         | 
    
        data/lib/epath/require_tree.rb
    CHANGED
    
    | @@ -1,22 +1,42 @@ | |
| 1 1 | 
             
            class Path
         | 
| 2 2 | 
             
              # @!group Requiring
         | 
| 3 3 |  | 
| 4 | 
            -
              # Requires all .rb files recursively  | 
| 5 | 
            -
              #  | 
| 6 | 
            -
               | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
               | 
| 4 | 
            +
              # Requires all .rb files recursively under +directory+
         | 
| 5 | 
            +
              # (or the current file's directory if not given).
         | 
| 6 | 
            +
              #
         | 
| 7 | 
            +
              # The order of requires is alphabetical,
         | 
| 8 | 
            +
              # but files having the same basename as a directory
         | 
| 9 | 
            +
              # are required before files in this directory.
         | 
| 10 | 
            +
              #
         | 
| 11 | 
            +
              #   # in bar.rb
         | 
| 12 | 
            +
              #   Path.require_tree
         | 
| 13 | 
            +
              #   # require in this order:
         | 
| 14 | 
            +
              #   # foo.rb
         | 
| 15 | 
            +
              #   # foo/ext.rb
         | 
| 16 | 
            +
              #   # foo/sub.rb
         | 
| 17 | 
            +
              #
         | 
| 18 | 
            +
              # @param directory [String] the directory to search,
         | 
| 19 | 
            +
              #                           or the current file's directory.
         | 
| 20 | 
            +
              # @option options [Array<String>] :except ([])
         | 
| 21 | 
            +
              #   a list of prefixes to ignore, relative to +directory+.
         | 
| 22 | 
            +
              def self.require_tree(directory = nil, options = {})
         | 
| 23 | 
            +
                directory, options = nil, directory if Hash === directory
         | 
| 24 | 
            +
                source = Path.file(caller)
         | 
| 25 | 
            +
                directory = Path.relative(directory || source.dir, caller)
         | 
| 26 | 
            +
                except = options[:except] || []
         | 
| 14 27 |  | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 28 | 
            +
                directory.glob('**/*.rb').reject { |path|
         | 
| 29 | 
            +
                  except.any? { |prefix| (path % directory).path.start_with?(prefix) }
         | 
| 30 | 
            +
                }.sort! { |a,b|
         | 
| 31 | 
            +
                  if b.inside?(a.rm_ext)
         | 
| 32 | 
            +
                    -1
         | 
| 33 | 
            +
                  elsif a.inside?(b.rm_ext)
         | 
| 34 | 
            +
                    +1
         | 
| 35 | 
            +
                  else
         | 
| 36 | 
            +
                    a <=> b
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
                }.each { |file|
         | 
| 39 | 
            +
                  require file.path unless source == file
         | 
| 40 | 
            +
                }
         | 
| 21 41 | 
             
              end
         | 
| 22 42 | 
             
            end
         | 
    
        data/lib/epath/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,41 +1,49 @@ | |
| 1 | 
            -
            --- !ruby/object:Gem::Specification
         | 
| 1 | 
            +
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: epath
         | 
| 3 | 
            -
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
               | 
| 3 | 
            +
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            +
              hash: 15
         | 
| 5 5 | 
             
              prerelease: 
         | 
| 6 | 
            +
              segments: 
         | 
| 7 | 
            +
              - 0
         | 
| 8 | 
            +
              - 4
         | 
| 9 | 
            +
              - 0
         | 
| 10 | 
            +
              version: 0.4.0
         | 
| 6 11 | 
             
            platform: ruby
         | 
| 7 | 
            -
            authors:
         | 
| 12 | 
            +
            authors: 
         | 
| 8 13 | 
             
            - eregon
         | 
| 9 14 | 
             
            autorequire: 
         | 
| 10 15 | 
             
            bindir: bin
         | 
| 11 16 | 
             
            cert_chain: []
         | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 17 | 
            +
             | 
| 18 | 
            +
            date: 2012-07-04 00:00:00 +02:00
         | 
| 19 | 
            +
            default_executable: 
         | 
| 20 | 
            +
            dependencies: 
         | 
| 21 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 15 22 | 
             
              name: rspec
         | 
| 16 | 
            -
              requirement: !ruby/object:Gem::Requirement
         | 
| 17 | 
            -
                none: false
         | 
| 18 | 
            -
                requirements:
         | 
| 19 | 
            -
                - - ! '>='
         | 
| 20 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 21 | 
            -
                    version: '0'
         | 
| 22 | 
            -
              type: :development
         | 
| 23 23 | 
             
              prerelease: false
         | 
| 24 | 
            -
               | 
| 24 | 
            +
              requirement: &id001 !ruby/object:Gem::Requirement 
         | 
| 25 25 | 
             
                none: false
         | 
| 26 | 
            -
                requirements:
         | 
| 27 | 
            -
                - -  | 
| 28 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 29 | 
            -
                     | 
| 26 | 
            +
                requirements: 
         | 
| 27 | 
            +
                - - ">="
         | 
| 28 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 29 | 
            +
                    hash: 3
         | 
| 30 | 
            +
                    segments: 
         | 
| 31 | 
            +
                    - 0
         | 
| 32 | 
            +
                    version: "0"
         | 
| 33 | 
            +
              type: :development
         | 
| 34 | 
            +
              version_requirements: *id001
         | 
| 30 35 | 
             
            description: 
         | 
| 31 36 | 
             
            email: eregontp@gmail.com
         | 
| 32 37 | 
             
            executables: []
         | 
| 38 | 
            +
             | 
| 33 39 | 
             
            extensions: []
         | 
| 40 | 
            +
             | 
| 34 41 | 
             
            extra_rdoc_files: []
         | 
| 35 | 
            -
             | 
| 42 | 
            +
             | 
| 43 | 
            +
            files: 
         | 
| 44 | 
            +
            - lib/epath/compatibility.rb
         | 
| 36 45 | 
             
            - lib/epath/dir.rb
         | 
| 37 46 | 
             
            - lib/epath/file.rb
         | 
| 38 | 
            -
            - lib/epath/file_dir.rb
         | 
| 39 47 | 
             
            - lib/epath/file_predicates.rb
         | 
| 40 48 | 
             
            - lib/epath/fileutils.rb
         | 
| 41 49 | 
             
            - lib/epath/find.rb
         | 
| @@ -51,29 +59,39 @@ files: | |
| 51 59 | 
             
            - README.md
         | 
| 52 60 | 
             
            - LICENSE
         | 
| 53 61 | 
             
            - epath.gemspec
         | 
| 62 | 
            +
            has_rdoc: true
         | 
| 54 63 | 
             
            homepage: https://github.com/eregon/epath
         | 
| 55 64 | 
             
            licenses: []
         | 
| 65 | 
            +
             | 
| 56 66 | 
             
            post_install_message: 
         | 
| 57 67 | 
             
            rdoc_options: []
         | 
| 58 | 
            -
             | 
| 68 | 
            +
             | 
| 69 | 
            +
            require_paths: 
         | 
| 59 70 | 
             
            - lib
         | 
| 60 | 
            -
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 71 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement 
         | 
| 61 72 | 
             
              none: false
         | 
| 62 | 
            -
              requirements:
         | 
| 63 | 
            -
              - -  | 
| 64 | 
            -
                - !ruby/object:Gem::Version
         | 
| 65 | 
            -
                   | 
| 66 | 
            -
             | 
| 73 | 
            +
              requirements: 
         | 
| 74 | 
            +
              - - ">="
         | 
| 75 | 
            +
                - !ruby/object:Gem::Version 
         | 
| 76 | 
            +
                  hash: 3
         | 
| 77 | 
            +
                  segments: 
         | 
| 78 | 
            +
                  - 0
         | 
| 79 | 
            +
                  version: "0"
         | 
| 80 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement 
         | 
| 67 81 | 
             
              none: false
         | 
| 68 | 
            -
              requirements:
         | 
| 69 | 
            -
              - -  | 
| 70 | 
            -
                - !ruby/object:Gem::Version
         | 
| 71 | 
            -
                   | 
| 82 | 
            +
              requirements: 
         | 
| 83 | 
            +
              - - ">="
         | 
| 84 | 
            +
                - !ruby/object:Gem::Version 
         | 
| 85 | 
            +
                  hash: 3
         | 
| 86 | 
            +
                  segments: 
         | 
| 87 | 
            +
                  - 0
         | 
| 88 | 
            +
                  version: "0"
         | 
| 72 89 | 
             
            requirements: []
         | 
| 90 | 
            +
             | 
| 73 91 | 
             
            rubyforge_project: 
         | 
| 74 | 
            -
            rubygems_version: 1. | 
| 92 | 
            +
            rubygems_version: 1.6.2
         | 
| 75 93 | 
             
            signing_key: 
         | 
| 76 94 | 
             
            specification_version: 3
         | 
| 77 95 | 
             
            summary: a Path manipulation library
         | 
| 78 96 | 
             
            test_files: []
         | 
| 79 | 
            -
             | 
| 97 | 
            +
             |