epath 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +25 -0
- data/lib/epath.rb +35 -0
- data/lib/epath/fileutils.rb +0 -6
- data/lib/epath/identity.rb +11 -13
- data/lib/epath/implementation.rb +71 -15
- data/lib/epath/io.rb +33 -4
- data/lib/epath/parts.rb +2 -2
- data/lib/epath/require_tree.rb +1 -1
- data/lib/epath/version.rb +1 -1
- metadata +2 -2
data/README.md
CHANGED
@@ -17,6 +17,7 @@ Also, using a path library like this avoid to remember in which class the functi
|
|
17
17
|
|
18
18
|
* [GitHub](https://github.com/eregon/epath)
|
19
19
|
* [YARD Documentation](http://rubydoc.info/github/eregon/epath/master/file/README.md)
|
20
|
+
* [Changelog](https://github.com/eregon/epath/blob/master/Changelog.md)
|
20
21
|
|
21
22
|
## API
|
22
23
|
|
@@ -144,6 +145,30 @@ Path.backfind('.[.git]') # => the root of this repository
|
|
144
145
|
|
145
146
|
* Path.require\_tree: require all .rb files recursively (in alphabetic order)
|
146
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/epath/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 were `+` 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 were `+` is used as #join.
|
171
|
+
|
147
172
|
## Status
|
148
173
|
|
149
174
|
This is still in the early development stage, you should expect many additions and some changes.
|
data/lib/epath.rb
CHANGED
@@ -103,6 +103,41 @@ class Path
|
|
103
103
|
result/path if result
|
104
104
|
end
|
105
105
|
|
106
|
+
# Relocates this path somewhere else.
|
107
|
+
#
|
108
|
+
# Without a block, this method is a simple shorcut for a longer
|
109
|
+
# expression that proves difficult to remember in practice:
|
110
|
+
#
|
111
|
+
# to / (self.sub_ext(new_ext) % from)
|
112
|
+
#
|
113
|
+
# That is, it relocates the original path to a target folder +to+
|
114
|
+
# appended with the relative path from a source folder +from+. An
|
115
|
+
# optional new extension can also be specified, as it is a common
|
116
|
+
# use case.
|
117
|
+
#
|
118
|
+
# With a block, the relative path is passed to the block for user
|
119
|
+
# update, without the last extension. +new_ext+ is added after (or
|
120
|
+
# the original extension if not provided).
|
121
|
+
#
|
122
|
+
# from = Path('pictures')
|
123
|
+
# to = Path('output/public/thumbnails')
|
124
|
+
# earth = from / 'nature/earth.jpg'
|
125
|
+
#
|
126
|
+
# earth.relocate(from, to)
|
127
|
+
# # => #<Path output/public/thumbnails/nature/earth.jpg>
|
128
|
+
#
|
129
|
+
# earth.relocate(from, to, '.png') { |rel|
|
130
|
+
# "#{rel}-200"
|
131
|
+
# }
|
132
|
+
# # => #<Path output/public/thumbnails/nature/earth-200.png>
|
133
|
+
def relocate(from, to, new_ext = ext, &updater)
|
134
|
+
updater ||= lambda { |path| path }
|
135
|
+
renamer = lambda { |rel|
|
136
|
+
Path(updater.call(rel.rm_ext)).add_ext(new_ext)
|
137
|
+
}
|
138
|
+
to / renamer.call(self % from)
|
139
|
+
end
|
140
|
+
|
106
141
|
# Setup
|
107
142
|
register_loader 'yml', 'yaml' do |path|
|
108
143
|
require 'yaml'
|
data/lib/epath/fileutils.rb
CHANGED
@@ -33,12 +33,6 @@ class Path
|
|
33
33
|
end
|
34
34
|
alias :safe_unlink :rm_f
|
35
35
|
|
36
|
-
# Removes the file or directory recursively, using +FileUtils.rm_r+.
|
37
|
-
def rm_r
|
38
|
-
FileUtils.rm_r(@path)
|
39
|
-
self
|
40
|
-
end
|
41
|
-
|
42
36
|
# Removes the file or directory recursively, ignoring errors,
|
43
37
|
# using +FileUtils.rm_f+.
|
44
38
|
def rm_rf
|
data/lib/epath/identity.rb
CHANGED
@@ -22,18 +22,27 @@ class Path
|
|
22
22
|
|
23
23
|
# @!group Identity
|
24
24
|
|
25
|
+
# Returns the +path+ as a String.
|
26
|
+
# {#path} is implemented for better readability (+file.path+ instead of +file.to_s+) and as an accessor.
|
27
|
+
# {#to_path} is implemented so Path objects are usable with +open+, etc.
|
28
|
+
# {#to_str} is implemented so Path objects are usable with +open+, etc with Ruby 1.8 (it is not defined in Ruby 1.9).
|
29
|
+
attr_reader :path
|
30
|
+
alias :to_s :path
|
31
|
+
alias :to_path :path
|
32
|
+
alias :to_str :path if RUBY_VERSION < '1.9'
|
33
|
+
|
25
34
|
# Compare this path with +other+. The comparison is string-based.
|
26
35
|
# Be aware that two different paths (+foo.txt+ and +./foo.txt+)
|
27
36
|
# can refer to the same file.
|
28
37
|
def == other
|
29
|
-
Path === other and @path == other.
|
38
|
+
Path === other and @path == other.path
|
30
39
|
end
|
31
40
|
alias :eql? :==
|
32
41
|
|
33
42
|
# Provides for comparing paths, case-sensitively.
|
34
43
|
def <=>(other)
|
35
44
|
return nil unless Path === other
|
36
|
-
@path.tr('/', "\0") <=> other.
|
45
|
+
@path.tr('/', "\0") <=> other.path.tr('/', "\0")
|
37
46
|
end
|
38
47
|
|
39
48
|
# The hash value of the +path+.
|
@@ -41,17 +50,6 @@ class Path
|
|
41
50
|
@path.hash
|
42
51
|
end
|
43
52
|
|
44
|
-
# Returns the +path+ as a String.
|
45
|
-
def to_s
|
46
|
-
@path
|
47
|
-
end
|
48
|
-
|
49
|
-
# to_path is implemented so Path objects are usable with File.open, etc.
|
50
|
-
alias :to_path :to_s
|
51
|
-
|
52
|
-
# to_str is implemented so Path objects are usable with File.open, etc in Ruby 1.8.
|
53
|
-
alias :to_str :to_s if RUBY_VERSION < '1.9'
|
54
|
-
|
55
53
|
# Returns the +path+ as a Symbol.
|
56
54
|
def to_sym
|
57
55
|
@path.to_sym
|
data/lib/epath/implementation.rb
CHANGED
@@ -39,6 +39,19 @@ class Path
|
|
39
39
|
init
|
40
40
|
end
|
41
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
|
+
|
42
55
|
# Marshal dumping.
|
43
56
|
def marshal_dump
|
44
57
|
@path
|
@@ -50,20 +63,17 @@ class Path
|
|
50
63
|
init
|
51
64
|
end
|
52
65
|
|
53
|
-
# Returns
|
66
|
+
# Returns a cleaned version of +self+ with consecutive slashes and useless dots removed.
|
54
67
|
# The filesystem is not accessed.
|
55
68
|
#
|
56
69
|
# If +consider_symlink+ is +true+, then a more conservative algorithm is used
|
57
70
|
# to avoid breaking symbolic linkages. This may retain more +..+
|
58
71
|
# entries than absolutely necessary, but without accessing the filesystem,
|
59
72
|
# this can't be avoided. See {#realpath}.
|
60
|
-
def
|
61
|
-
|
62
|
-
cleanpath_conservative
|
63
|
-
else
|
64
|
-
cleanpath_aggressive
|
65
|
-
end
|
73
|
+
def clean(consider_symlink = false)
|
74
|
+
consider_symlink ? cleanpath_conservative : cleanpath_aggressive
|
66
75
|
end
|
76
|
+
alias :cleanpath :clean
|
67
77
|
|
68
78
|
# #parent returns the parent directory.
|
69
79
|
# This can be chained.
|
@@ -81,12 +91,58 @@ class Path
|
|
81
91
|
def /(other)
|
82
92
|
Path.new(plus(@path, other.to_s))
|
83
93
|
end
|
84
|
-
alias :+ :/
|
85
94
|
|
86
|
-
# Path
|
95
|
+
# Configures the behavior of {Path#+}. The default is +:warning+.
|
96
|
+
#
|
97
|
+
# Path + :defined # aliased to Path#/
|
98
|
+
# Path + :warning # calls Path#/ but warns
|
99
|
+
# Path + :error # not defined
|
100
|
+
# Path + :string # like String#+. Warns if $VERBOSE (-w)
|
101
|
+
#
|
102
|
+
# @param config [:defined, :warning, :error, :string] the configuration value
|
103
|
+
def Path.+(config)
|
104
|
+
unless [:defined, :warning, :error, :string].include? config
|
105
|
+
raise ArgumentError, "Invalid configuration: #{config.inspect}"
|
106
|
+
end
|
107
|
+
if @plus_configured
|
108
|
+
raise "Path.+ has already been called: #{@plus_configured}"
|
109
|
+
end
|
110
|
+
remove_method :+ if method_defined? :+
|
111
|
+
case config
|
112
|
+
when :defined
|
113
|
+
alias :+ :/
|
114
|
+
when :warning
|
115
|
+
def +(other)
|
116
|
+
warn 'Warning: use of deprecated Path#+ as Path#/: ' <<
|
117
|
+
"#{inspect} + #{other.inspect}\n#{caller.first}"
|
118
|
+
self / other
|
119
|
+
end
|
120
|
+
when :error
|
121
|
+
# nothing to do, the method has been removed
|
122
|
+
when :string
|
123
|
+
def +(other)
|
124
|
+
warn 'Warning: use of deprecated Path#+ as String#+: ' <<
|
125
|
+
"#{inspect} + #{other.inspect}\n#{caller.first}" if $VERBOSE
|
126
|
+
Path(to_s + other.to_s)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
@plus_configured = caller.first
|
130
|
+
end
|
131
|
+
|
132
|
+
@plus_configured = nil # Initialization
|
133
|
+
Path + :warning
|
134
|
+
@plus_configured = nil # Let the user overrides this default configuration
|
135
|
+
|
136
|
+
# @!method +(other)
|
137
|
+
# The behavior depends on the configuration with Path.{Path.+}.
|
138
|
+
# It might behave as {Path#/}, String#+, give warnings,
|
139
|
+
# or not be defined at all.
|
140
|
+
|
141
|
+
# Joins paths.
|
87
142
|
#
|
88
|
-
#
|
89
|
-
#
|
143
|
+
# path0.join(path1, ..., pathN)
|
144
|
+
# # is the same as
|
145
|
+
# path0 / path1 / ... / pathN
|
90
146
|
def join(*args)
|
91
147
|
args.unshift self
|
92
148
|
result = Path.new(args.pop)
|
@@ -107,8 +163,8 @@ class Path
|
|
107
163
|
#
|
108
164
|
# ArgumentError is raised when it cannot find a relative path.
|
109
165
|
def relative_path_from(base_directory)
|
110
|
-
dest_directory =
|
111
|
-
base_directory = Path.new(base_directory).
|
166
|
+
dest_directory = clean.path
|
167
|
+
base_directory = Path.new(base_directory).clean.path
|
112
168
|
dest_prefix = dest_directory
|
113
169
|
dest_names = []
|
114
170
|
while r = chop_basename(dest_prefix)
|
@@ -148,12 +204,12 @@ class Path
|
|
148
204
|
|
149
205
|
# remove the leading . of +ext+ if present.
|
150
206
|
def pure_ext(ext)
|
151
|
-
ext.start_with?('.') ? ext[1..-1] : ext
|
207
|
+
ext = ext.to_s and ext.start_with?('.') ? ext[1..-1] : ext
|
152
208
|
end
|
153
209
|
|
154
210
|
# add a leading . to +ext+ if missing. Returns '' if +ext+ is empty.
|
155
211
|
def dotted_ext(ext)
|
156
|
-
(ext.empty? or ext.start_with?('.')) ? ext : ".#{ext}"
|
212
|
+
ext = ext.to_s and (ext.empty? or ext.start_with?('.')) ? ext : ".#{ext}"
|
157
213
|
end
|
158
214
|
end
|
159
215
|
|
data/lib/epath/io.rb
CHANGED
@@ -14,20 +14,22 @@ class Path
|
|
14
14
|
end
|
15
15
|
alias :lines :each_line
|
16
16
|
|
17
|
-
# Returns all data from the file, or the first +
|
17
|
+
# Returns all data from the file, or the first +bytes+ bytes if specified.
|
18
18
|
# See +IO.read+.
|
19
19
|
def read(*args)
|
20
20
|
IO.read(@path, *args)
|
21
21
|
end
|
22
22
|
|
23
|
-
# Returns all the bytes from the file, or the first +N+ if specified.
|
24
|
-
# See +IO.binread+.
|
25
23
|
if IO.respond_to? :binread
|
24
|
+
# Returns all the bytes from the file, or the first +N+ if specified.
|
25
|
+
# See +IO.binread+.
|
26
26
|
def binread(*args)
|
27
27
|
IO.binread(@path, *args)
|
28
28
|
end
|
29
29
|
else
|
30
|
-
|
30
|
+
def binread(*args)
|
31
|
+
open('rb', &:read)
|
32
|
+
end
|
31
33
|
end
|
32
34
|
|
33
35
|
# Returns all the lines from the file. See +IO.readlines+.
|
@@ -51,6 +53,17 @@ class Path
|
|
51
53
|
end
|
52
54
|
end
|
53
55
|
|
56
|
+
if IO.respond_to? :binwrite
|
57
|
+
# Writes +contents+ to +self+. See +IO.binwrite+.
|
58
|
+
def binwrite(contents, *open_args)
|
59
|
+
IO.binwrite(@path, contents, *open_args)
|
60
|
+
end
|
61
|
+
else
|
62
|
+
def binwrite(contents, *open_args)
|
63
|
+
open('wb', *open_args) { |f| f.write(contents) }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
54
67
|
if IO.respond_to? :write and !RUBY_DESCRIPTION.start_with?('jruby')
|
55
68
|
# Appends +contents+ to +self+. See +IO.write+ or +IO#write+.
|
56
69
|
def append(contents, open_args = {})
|
@@ -62,4 +75,20 @@ class Path
|
|
62
75
|
open('a', *open_args) { |f| f.write(contents) }
|
63
76
|
end
|
64
77
|
end
|
78
|
+
|
79
|
+
# Returns the first +bytes+ bytes of the file.
|
80
|
+
# If the file size is smaller than +bytes+, return the whole contents.
|
81
|
+
def head(bytes)
|
82
|
+
read(bytes)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Returns the last +bytes+ bytes of the file.
|
86
|
+
# If the file size is smaller than +bytes+, return the whole contents.
|
87
|
+
def tail(bytes)
|
88
|
+
return read if size < bytes
|
89
|
+
open { |f|
|
90
|
+
f.seek(-bytes, IO::SEEK_END)
|
91
|
+
f.read
|
92
|
+
}
|
93
|
+
end
|
65
94
|
end
|
data/lib/epath/parts.rb
CHANGED
@@ -44,7 +44,7 @@ class Path
|
|
44
44
|
#
|
45
45
|
# Path('file').add_extension('txt') # => #<Path file.txt>
|
46
46
|
def add_extension(ext)
|
47
|
-
return self if ext.empty?
|
47
|
+
return self if ext.to_s.empty?
|
48
48
|
Path.new @path+dotted_ext(ext)
|
49
49
|
end
|
50
50
|
alias :add_ext :add_extension
|
@@ -64,7 +64,7 @@ class Path
|
|
64
64
|
#
|
65
65
|
# Path('main.c++').replace_extension('cc') # => #<Path main.cc>
|
66
66
|
def replace_extension(ext)
|
67
|
-
return without_extension if ext.empty?
|
67
|
+
return without_extension if ext.to_s.empty?
|
68
68
|
Path.new(@path[0..-extname.size-1] << dotted_ext(ext))
|
69
69
|
end
|
70
70
|
alias :sub_ext :replace_extension
|
data/lib/epath/require_tree.rb
CHANGED
@@ -17,6 +17,6 @@ class Path
|
|
17
17
|
# It is not a real private method because {Path.require_tree}
|
18
18
|
# (so the {Path} class) needs to be able to call it.
|
19
19
|
def require_tree(source = nil)
|
20
|
-
glob('**/*.rb').sort.each { |file| require file.expand(dir).
|
20
|
+
glob('**/*.rb').sort.each { |file| require file.expand(dir).path unless file == source }
|
21
21
|
end
|
22
22
|
end
|
data/lib/epath/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: epath
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-06-
|
12
|
+
date: 2012-06-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|