path 1.3.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/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (C) 2011-2012 Benoit Daloze
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,183 @@
1
+ # Path - a Path manipulation library
2
+
3
+ [Path](http://rubydoc.info/github/eregon/path/master/Path) is a library to manage paths.
4
+ It is similar to Pathname, but has some extra goodness.
5
+ The method names are intended to be short and explicit, and avoid too much duplication like having 'name' or 'path' in the method name.
6
+
7
+ I believe the object-oriented approach to manipulate paths is very elegant and useful.
8
+ Paths are naturally the subject of their methods and even if they are simple Strings behind, they carry way much more information and deserve a first-class status.
9
+
10
+ Also, using a path library like this avoid to remember in which class the functionality is implemented, everything is in one place (if not, please open an issue!).
11
+
12
+ ## Installation
13
+
14
+ gem install path
15
+
16
+ ## Links
17
+
18
+ * [GitHub](https://github.com/eregon/path)
19
+ * [YARD Documentation](http://rubydoc.info/github/eregon/path/master/file/README.md)
20
+ * [Changelog](https://github.com/eregon/path/blob/master/Changelog.md)
21
+
22
+ ## API
23
+
24
+ See the [Path](http://rubydoc.info/github/eregon/path/master/Path) class documentation for details.
25
+
26
+ All the useful methods of `File` (and so `IO`) and `Dir` should be included.
27
+ Most methods of `FileUtils` should be there too.
28
+
29
+ ### creation
30
+
31
+ ``` ruby
32
+ Path.new('/usr/bin')
33
+ Path['/usr/bin']
34
+ Path('/usr/bin') # unless NO_PATH_GLOBAL_FUNCTION is defined
35
+
36
+ Path.new('~myuser/path') # expanded if it begins with ~
37
+
38
+ # Separators are replaced by / on systems having File::ALT_SEPARATOR
39
+ Path.new('win\sepa\rator') # => #<Path win/sepa/rator>
40
+
41
+ Path.new('/usr', 'bin')
42
+ %w[foo bar].map(&Path) # => [Path('foo'), Path('bar')]
43
+ ```
44
+
45
+ ``` ruby
46
+ Path.file # == Path(__FILE__).expand
47
+ Path.dir # == Path(File.dirname(__FILE__)).expand
48
+ Path.relative(path) # == Path(File.expand_path("../#{path}", __FILE__))
49
+ Path.home or Path.~ # == Path(File.expand_path('~'))
50
+ Path.~(user) # == Path(File.expand_path("~#{user}"))
51
+ ```
52
+
53
+ ### temporary
54
+
55
+ ``` ruby
56
+ Path.tmpfile
57
+ Path.tmpdir
58
+ ```
59
+
60
+ ### aliases
61
+
62
+ * expand => expand\_path
63
+ * relative\_to => relative\_path\_from
64
+
65
+ ### parts
66
+
67
+ Path can split a path in two ways:
68
+
69
+ The first way is the one done by File methods (dirname, basename, extname).
70
+
71
+ The second is Path's own way in which the base is given without the extension and the extension is given without the leading dot.
72
+ The rationale behind this is to have a true three-components path, splitting on the / and the . (See [this issue](https://github.com/eregon/path/pull/8#issuecomment-3499030) for details)
73
+
74
+ dirname basename
75
+ ____________ ______
76
+ / \ / \
77
+ /some/path/dir/file.ext
78
+ \____________/ \__/ \_/
79
+ dir base ext
80
+
81
+ path = dirname / basename
82
+ path = dirname / basename(extname) extname
83
+ path = dir / base [. ext]
84
+
85
+ * dirname: "/some/path/dir"
86
+ * basename: "file.ext"
87
+ * extname: ".ext"
88
+
89
+ <!-- -->
90
+
91
+ * dir: alias of dirname: "/some/paths/dir"
92
+ * base: basename(extname), the basename without the extension: "file"
93
+ * ext: extname without the leading dot: "ext"
94
+
95
+ <!-- -->
96
+
97
+ ### join
98
+
99
+ * join(*parts)
100
+ * /: join paths (as Pathname#+)
101
+
102
+ ```ruby
103
+ Path('/usr')/'bin'
104
+ ```
105
+
106
+ ### extensions
107
+
108
+ * add\_ext / add\_extension
109
+ * rm\_ext / without\_extension
110
+ * sub\_ext(new\_ext) / replace\_extension(new\_ext)
111
+
112
+ ### glob
113
+
114
+ * children: files under self, without . and ..
115
+ * glob: relative glob to self, yield absolute paths
116
+
117
+ ### structure
118
+
119
+ * parent: parent directory (don't use #dirname more than once, use #parent instead)
120
+ * ascend, ancestors: self and all the parent directories
121
+ * descend: in the reverse order
122
+ * backfind: ascends the parents until it finds the given path
123
+
124
+ ``` ruby
125
+ # Path.backfind is Path.here.backfind
126
+ Path.backfind('lib') # => Path's lib folder
127
+
128
+ # It accepts XPath-like context
129
+ Path.backfind('.[.git]') # => the root of this repository
130
+ ```
131
+
132
+ ### IO
133
+
134
+ * read
135
+ * write(contents)
136
+ * append(contents)
137
+
138
+ ### management
139
+
140
+ * mkdir
141
+ * mkdir\_p
142
+ * rm\_rf
143
+
144
+ ### require
145
+
146
+ * Path.require\_tree: require all .rb files recursively (in alphabetic order)
147
+
148
+ ### relocate
149
+
150
+ ``` ruby
151
+ from = Path('pictures')
152
+ to = Path('output/public/thumbnails')
153
+ earth = Path('pictures/nature/earth.jpg')
154
+
155
+ earth.relocate(from, to, '.png') { |rel| "#{rel}-200" }
156
+ # => #<Path output/public/thumbnails/nature/earth-200.png>
157
+ ```
158
+
159
+ ## Transition from String/Pathname
160
+
161
+ One aim of Path is to help the user make the transition coming from
162
+ String (not using a path library), Pathname, or another library.
163
+
164
+ To this intend, [`Path + config`](http://rubydoc.info/github/eregon/path/master/Path#%2B-class_method) allows to configure the behavior of `Path#+`.
165
+
166
+ Coming from String, one should use `Path + :string`, and run ruby with the verbose option (`-w`),
167
+ which will show where `+` is used as String concatenation.
168
+
169
+ Coming from a path library using `+` as #join, one should just use the default (`Path + :warning`),
170
+ which will show where `+` is used.
171
+
172
+ ## Status
173
+
174
+ This is still in the early development stage, you should expect many additions and some changes.
175
+
176
+ ## Author
177
+
178
+ Benoit Daloze - eregon
179
+
180
+ ## Contributors
181
+
182
+ Bernard Lambeau - blambeau
183
+ Ravil Bayramgalin - brainopia
@@ -0,0 +1,2 @@
1
+ # For compatibility with old gem name
2
+ require File.expand_path('../path.rb', __FILE__)
@@ -0,0 +1,159 @@
1
+ # Path - a Path manipulation library
2
+
3
+ Dir.glob(File.expand_path('../path/*.rb',__FILE__)) { |file| require file }
4
+
5
+ require 'tempfile'
6
+
7
+ class Path
8
+ class << self
9
+ # {Path} to the current file +Path(__FILE__)+.
10
+ def file(from = nil)
11
+ from ||= caller # this can not be moved as a default argument, JRuby optimizes it
12
+ # v This : is there to define a group without capturing
13
+ new(from.first.rpartition(/:\d+(?:$|:in )/).first).expand
14
+ end
15
+ alias :here :file
16
+
17
+ # {Path} to the directory of this file: +Path(__FILE__).dir+.
18
+ def dir(from = nil)
19
+ from ||= caller # this can not be moved as a default argument, JRuby optimizes it
20
+ file(from).dir
21
+ end
22
+
23
+ # {Path} relative to the directory of this file.
24
+ def relative(path, from = nil)
25
+ from ||= caller # this can not be moved as a default argument, JRuby optimizes it
26
+ new(path).expand dir(from)
27
+ end
28
+
29
+ # A {Path} to the home directory of +user+ (defaults to the current user).
30
+ # The form with an argument (+user+) is not supported on Windows.
31
+ def ~(user = '')
32
+ new("~#{user}")
33
+ end
34
+ alias :home :~
35
+
36
+ # Same as +Path.file.backfind(path)+. See {#backfind}.
37
+ def backfind(path)
38
+ file(caller).backfind(path)
39
+ end
40
+
41
+ # @yieldparam [Path] tmpfile
42
+ def tmpfile(basename = '', tmpdir = nil, options = nil)
43
+ tempfile = Tempfile.new(basename, *[tmpdir, options].compact)
44
+ file = new tempfile
45
+ if block_given?
46
+ begin
47
+ yield file
48
+ ensure
49
+ tempfile.close!
50
+ end
51
+ end
52
+ file
53
+ end
54
+ alias :tempfile :tmpfile
55
+
56
+ # @yieldparam [Path] tmpdir
57
+ def tmpdir(prefix_suffix = nil, *rest)
58
+ require 'tmpdir'
59
+ dir = new Dir.mktmpdir(prefix_suffix, *rest)
60
+ if block_given?
61
+ begin
62
+ yield dir
63
+ ensure
64
+ FileUtils.remove_entry_secure(dir) rescue nil
65
+ end
66
+ end
67
+ dir
68
+ end
69
+
70
+ # @yieldparam [Path] tmpdir
71
+ def tmpchdir(prefix_suffix = nil, *rest)
72
+ tmpdir do |dir|
73
+ dir.chdir do
74
+ yield dir
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ # Whether +self+ is inside +ancestor+, such that +ancestor+ is an ancestor of +self+.
81
+ # This is pure String manipulation. Paths should be absolute.
82
+ # +self+ is considered to be inside itself.
83
+ def inside? ancestor
84
+ @path == ancestor.to_s or @path.start_with?("#{ancestor}/")
85
+ end
86
+
87
+ # The opposite of {#inside?}.
88
+ def outside? ancestor
89
+ !inside?(ancestor)
90
+ end
91
+
92
+ # Ascends the parents until it finds the given +path+.
93
+ #
94
+ # Path.backfind('lib') # => the lib folder
95
+ #
96
+ # It accepts an XPath-like context:
97
+ #
98
+ # Path.backfind('.[.git]') # => the root of the repository
99
+ def backfind(path)
100
+ condition = path[/\[(.*)\]$/, 1] || ''
101
+ path = $` unless condition.empty?
102
+
103
+ result = ancestors.find { |ancestor| (ancestor/path/condition).exist? }
104
+ result/path if result
105
+ end
106
+
107
+ # Relocates this path somewhere else.
108
+ #
109
+ # Without a block, this method is a simple shorcut for a longer
110
+ # expression that proves difficult to remember in practice:
111
+ #
112
+ # to / (self.sub_ext(new_ext) % from)
113
+ #
114
+ # That is, it relocates the original path to a target folder +to+
115
+ # appended with the relative path from a source folder +from+. An
116
+ # optional new extension can also be specified, as it is a common
117
+ # use case.
118
+ #
119
+ # With a block, the relative path is passed to the block for user
120
+ # update, without the last extension. +new_ext+ is added after (or
121
+ # the original extension if not provided).
122
+ #
123
+ # from = Path('pictures')
124
+ # to = Path('output/public/thumbnails')
125
+ # earth = from / 'nature/earth.jpg'
126
+ #
127
+ # earth.relocate(from, to)
128
+ # # => #<Path output/public/thumbnails/nature/earth.jpg>
129
+ #
130
+ # earth.relocate(from, to, '.png') { |rel|
131
+ # "#{rel}-200"
132
+ # }
133
+ # # => #<Path output/public/thumbnails/nature/earth-200.png>
134
+ def relocate(from, to, new_ext = ext, &updater)
135
+ updater ||= lambda { |path| path }
136
+ renamer = lambda { |rel|
137
+ Path(updater.call(rel.rm_ext)).add_ext(new_ext)
138
+ }
139
+ to / renamer.call(self % from)
140
+ end
141
+
142
+ # Setup
143
+ register_loader 'yml', 'yaml' do |path|
144
+ require 'yaml'
145
+ YAML.load_file(path)
146
+ end
147
+
148
+ register_loader 'json' do |path|
149
+ require 'json'
150
+ JSON.load(path.read)
151
+ end
152
+
153
+ register_loader 'gemspec' do |path|
154
+ eval path.read
155
+ end
156
+ end
157
+
158
+ # to meet everyone's expectations and for compatibility with old gem name
159
+ EPath = Path
@@ -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
@@ -0,0 +1,147 @@
1
+ class Path
2
+ class << self
3
+ # @!group Directory
4
+
5
+ # Returns or yields Path objects. See +Dir.glob+.
6
+ # @yieldparam [Path] path
7
+ def glob(pattern, flags = 0)
8
+ if block_given?
9
+ Dir.glob(pattern, flags) { |f| yield new(f) }
10
+ else
11
+ Dir.glob(pattern, flags).map(&Path)
12
+ end
13
+ end
14
+
15
+ # Returns the current working directory as a Path. See +Dir.getwd+.
16
+ def Path.getwd
17
+ new Dir.getwd
18
+ end
19
+ alias :pwd :getwd
20
+ end
21
+
22
+ # @!group Directory
23
+
24
+ # Iterates over the entries (files and subdirectories) in the directory.
25
+ #
26
+ # Path("/usr/local").each_entry { |entry| p entry } # =>
27
+ # #<Path .>
28
+ # #<Path ..>
29
+ # #<Path lib>
30
+ # #<Path share>
31
+ # # ...
32
+ #
33
+ # @deprecated Use {#each_child} instead.
34
+ # This method is deprecated since it is too low level and likely useless in Ruby.
35
+ # But it is there for the sake of compatibility with Dir.foreach and Pathname#each_entry.
36
+ # @yieldparam [Path] entry
37
+ def each_entry(&block)
38
+ Dir.foreach(@path) { |f| yield Path.new(f) }
39
+ end
40
+
41
+ # Create the referenced directory and returns self. See +Dir.mkdir+.
42
+ def mkdir(*args)
43
+ Dir.mkdir(@path, *args)
44
+ self
45
+ end
46
+
47
+ # Remove the referenced directory. See +Dir.rmdir+.
48
+ def rmdir
49
+ Dir.rmdir(@path)
50
+ end
51
+
52
+ # See +Dir.open+.
53
+ # @yieldparam [Dir] dir
54
+ def opendir(&block)
55
+ Dir.open(@path, &block)
56
+ end
57
+
58
+ # Returns or yields Path objects. See +Dir.glob+.
59
+ # @yieldparam [Path] path
60
+ def glob(pattern, flags = 0)
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
66
+ end
67
+
68
+ # Return the entries (files and subdirectories) in the directory.
69
+ # Each Path only contains the filename.
70
+ # The result may contain the current directory #<Path .> and the parent directory #<Path ..>.
71
+ #
72
+ # Path('/usr/local').entries
73
+ # # => [#<Path share>, #<Path lib>, #<Path .>, #<Path ..>, <Path bin>, ...]
74
+ #
75
+ # @deprecated Use {#children} instead.
76
+ # This method is deprecated since it is too low level and likely useless in Ruby.
77
+ # But it is there for the sake of compatibility with Dir.entries (and Pathname#entries).
78
+ def entries
79
+ Dir.entries(@path).map(&Path)
80
+ end
81
+
82
+ # Changes the current working directory of the process to self. See Dir.chdir.
83
+ # The recommended way to use it is to use the block form, or not use it all!
84
+ def chdir(&block)
85
+ Dir.chdir(@path, &block)
86
+ end
87
+
88
+ # Returns the children of the directory (files and subdirectories, not
89
+ # recursive) as an array of Path objects. By default, the returned
90
+ # paths will have enough information to access the files. If you set
91
+ # +with_directory+ to +false+, then the returned paths will contain the
92
+ # filename only.
93
+ #
94
+ # For example:
95
+ # pn = Path("/usr/lib/ruby/1.8")
96
+ # pn.children
97
+ # # -> [ #<Path /usr/lib/ruby/1.8/English.rb>,
98
+ # #<Path /usr/lib/ruby/1.8/Env.rb>,
99
+ # #<Path /usr/lib/ruby/1.8/abbrev.rb>, ... ]
100
+ # pn.children(false)
101
+ # # -> [ #<Path English.rb>, #<Path Env.rb>, #<Path abbrev.rb>, ... ]
102
+ #
103
+ # Note that the results never contain the entries +.+ and +..+ in
104
+ # the directory because they are not children.
105
+ def children(with_directory=true)
106
+ with_directory = false if @path == '.'
107
+ result = []
108
+ Dir.foreach(@path) { |e|
109
+ next if e == '.' || e == '..'
110
+ if with_directory
111
+ result << Path.new(@path, e)
112
+ else
113
+ result << Path.new(e)
114
+ end
115
+ }
116
+ result
117
+ end
118
+
119
+ # Iterates over the children of the directory (files and subdirectories, not recursive).
120
+ # By default, the yielded paths will have enough information to access the files.
121
+ # If you set +with_directory+ to +false+, then the returned paths will contain the filename only.
122
+ #
123
+ # Path("/usr/local").each_child { |f| p f } # =>
124
+ # #<Path /usr/local/share>
125
+ # #<Path /usr/local/bin>
126
+ # #<Path /usr/local/games>
127
+ # #<Path /usr/local/lib>
128
+ # #<Path /usr/local/include>
129
+ # #<Path /usr/local/sbin>
130
+ # #<Path /usr/local/src>
131
+ # #<Path /usr/local/man>
132
+ #
133
+ # Path("/usr/local").each_child(false) { |f| p f } # =>
134
+ # #<Path share>
135
+ # #<Path bin>
136
+ # #<Path games>
137
+ # #<Path lib>
138
+ # #<Path include>
139
+ # #<Path sbin>
140
+ # #<Path src>
141
+ # #<Path man>
142
+ #
143
+ # @yieldparam [Path] child
144
+ def each_child(with_directory=true, &b)
145
+ children(with_directory).each(&b)
146
+ end
147
+ end