epath 0.2.0 → 0.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/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
|