rubypath 0.1.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.
- checksums.yaml +7 -0
- data/LICENSE.txt +165 -0
- data/README.md +29 -0
- data/doc/file.README.html +111 -0
- data/lib/rubypath/backend/mock.rb +315 -0
- data/lib/rubypath/backend/sys.rb +139 -0
- data/lib/rubypath/backend.rb +87 -0
- data/lib/rubypath/comparison.rb +22 -0
- data/lib/rubypath/construction.rb +109 -0
- data/lib/rubypath/dir_operations.rb +76 -0
- data/lib/rubypath/extensions.rb +157 -0
- data/lib/rubypath/file_operations.rb +164 -0
- data/lib/rubypath/file_predicates.rb +32 -0
- data/lib/rubypath/identity.rb +59 -0
- data/lib/rubypath/io_operations.rb +82 -0
- data/lib/rubypath/mock.rb +42 -0
- data/lib/rubypath/path_operations.rb +253 -0
- data/lib/rubypath/path_predicates.rb +61 -0
- data/lib/rubypath/version.rb +11 -0
- data/lib/rubypath.rb +28 -0
- data/rubypath.gemspec +22 -0
- data/spec/rubypath/comparison_spec.rb +46 -0
- data/spec/rubypath/construction_spec.rb +101 -0
- data/spec/rubypath/dir_operations_spec.rb +146 -0
- data/spec/rubypath/extensions_spec.rb +270 -0
- data/spec/rubypath/file_operations_spec.rb +385 -0
- data/spec/rubypath/file_predicates_spec.rb +66 -0
- data/spec/rubypath/identity_spec.rb +21 -0
- data/spec/rubypath/io_operations_spec.rb +126 -0
- data/spec/rubypath/path_operations_spec.rb +383 -0
- data/spec/rubypath/path_predicates_spec.rb +75 -0
- data/spec/spec_helper.rb +42 -0
- data/spec/support/describe_method.rb +18 -0
- data/spec/support/with_backend.rb +31 -0
- metadata +107 -0
@@ -0,0 +1,139 @@
|
|
1
|
+
class Path::Backend
|
2
|
+
|
3
|
+
#
|
4
|
+
class Sys
|
5
|
+
|
6
|
+
def initialize(root = nil)
|
7
|
+
@root = ::File.expand_path root if root
|
8
|
+
@umask = File.umask
|
9
|
+
end
|
10
|
+
|
11
|
+
def quit
|
12
|
+
File.umask @umask
|
13
|
+
end
|
14
|
+
|
15
|
+
def home(user)
|
16
|
+
::File.expand_path "~#{user}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def getwd
|
20
|
+
::Dir.getwd
|
21
|
+
end
|
22
|
+
|
23
|
+
def user
|
24
|
+
require 'etc'
|
25
|
+
|
26
|
+
Etc.getlogin
|
27
|
+
end
|
28
|
+
|
29
|
+
def r(path)
|
30
|
+
return path unless @root
|
31
|
+
::File.expand_path("#{@root}/#{::File.expand_path(path)}")
|
32
|
+
end
|
33
|
+
|
34
|
+
def ur(path)
|
35
|
+
return path unless @root
|
36
|
+
|
37
|
+
if path.slice(0, @root.length) == @root
|
38
|
+
path.slice(@root.length, path.length - @root.length)
|
39
|
+
else
|
40
|
+
path
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def fs(path, obj, method, *args)
|
45
|
+
# puts "[FS] #{obj} #{method} #{args.inspect}"
|
46
|
+
obj.send method, *args
|
47
|
+
rescue Errno::ENOENT
|
48
|
+
raise Errno::ENOENT.new path
|
49
|
+
rescue Errno::EISDIR
|
50
|
+
raise Errno::EISDIR.new path
|
51
|
+
rescue Errno::ENOTDIR
|
52
|
+
raise Errno::ENOTDIR.new path
|
53
|
+
end
|
54
|
+
|
55
|
+
## OPERATIONS
|
56
|
+
|
57
|
+
def expand_path(path, base)
|
58
|
+
::File.expand_path path, base
|
59
|
+
end
|
60
|
+
|
61
|
+
def exists?(path)
|
62
|
+
fs path, ::File, :exists?, r(path)
|
63
|
+
end
|
64
|
+
|
65
|
+
def mkdir(path)
|
66
|
+
fs path, ::Dir, :mkdir, r(path)
|
67
|
+
end
|
68
|
+
|
69
|
+
def mkpath(path)
|
70
|
+
fs path, ::FileUtils, :mkdir_p, r(path)
|
71
|
+
end
|
72
|
+
|
73
|
+
def directory?(path)
|
74
|
+
fs path, ::File, :directory?, r(path)
|
75
|
+
end
|
76
|
+
|
77
|
+
def file?(path)
|
78
|
+
fs path, ::File, :file?, r(path)
|
79
|
+
end
|
80
|
+
|
81
|
+
def touch(path)
|
82
|
+
fs path, ::FileUtils, :touch, r(path)
|
83
|
+
end
|
84
|
+
|
85
|
+
def write(path, content, *args)
|
86
|
+
fs path, ::IO, :write, r(path), content, *args
|
87
|
+
end
|
88
|
+
|
89
|
+
def read(path, *args)
|
90
|
+
fs path, ::IO, :read, r(path), *args
|
91
|
+
end
|
92
|
+
|
93
|
+
def mtime(path)
|
94
|
+
fs path, ::File, :mtime, r(path)
|
95
|
+
end
|
96
|
+
|
97
|
+
def mtime=(path, time)
|
98
|
+
fs path, ::File, :utime, atime(path), time, r(path)
|
99
|
+
end
|
100
|
+
|
101
|
+
def atime(path)
|
102
|
+
fs path, ::File, :atime, r(path)
|
103
|
+
end
|
104
|
+
|
105
|
+
def atime=(path, time)
|
106
|
+
fs path, ::File, :utime, time, mtime(path), r(path)
|
107
|
+
end
|
108
|
+
|
109
|
+
def entries(path)
|
110
|
+
fs path, ::Dir, :entries, r(path)
|
111
|
+
end
|
112
|
+
|
113
|
+
def glob(pattern, flags = 0, &block)
|
114
|
+
if block_given?
|
115
|
+
fs pattern, ::Dir, :glob, r(pattern), flags do |path|
|
116
|
+
yield ur(path)
|
117
|
+
end
|
118
|
+
else
|
119
|
+
fs(pattern, ::Dir, :glob, r(pattern), flags).map{|path| ur path }
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def get_umask
|
124
|
+
File.umask
|
125
|
+
end
|
126
|
+
|
127
|
+
def set_umask(mask)
|
128
|
+
File.umask mask
|
129
|
+
end
|
130
|
+
|
131
|
+
def mode(path)
|
132
|
+
fs(path, ::File, :stat, r(path)).mode & 0777
|
133
|
+
end
|
134
|
+
|
135
|
+
def chmod(path, mode)
|
136
|
+
fs path, ::File, :chmod, mode, r(path)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
class Path
|
2
|
+
class Backend
|
3
|
+
class << self
|
4
|
+
def instance
|
5
|
+
@instance ||= new
|
6
|
+
end
|
7
|
+
|
8
|
+
def delegate(mth)
|
9
|
+
define_method mth do |*args|
|
10
|
+
backend.send mth, *args
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def mock(*args, &block)
|
15
|
+
self.instance.mock(*args, &block)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_accessor :backend
|
20
|
+
def initialize
|
21
|
+
self.backend = Backend::Sys.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def mock(opts = {}, &block)
|
25
|
+
if opts[:root]
|
26
|
+
# Use real file system scoped to given directory (chroot like)
|
27
|
+
if opts[:root] == :tmp
|
28
|
+
::Dir.mktmpdir('rubypath') do |path|
|
29
|
+
use_backend Backend::Sys.new(path), &block
|
30
|
+
end
|
31
|
+
else
|
32
|
+
use_backend Backend::Sys.new(opts[:root]), &block
|
33
|
+
end
|
34
|
+
else
|
35
|
+
# Use mock FS
|
36
|
+
use_backend Backend::Mock.new, &block
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def use_backend(be)
|
41
|
+
old_backend, self.backend = backend, be
|
42
|
+
yield
|
43
|
+
backend.quit if backend.respond_to? :quit
|
44
|
+
self.backend = old_backend
|
45
|
+
end
|
46
|
+
|
47
|
+
delegate :expand_path
|
48
|
+
delegate :getwd
|
49
|
+
delegate :exists?
|
50
|
+
delegate :mkdir
|
51
|
+
delegate :mkpath
|
52
|
+
delegate :directory?
|
53
|
+
delegate :file?
|
54
|
+
delegate :touch
|
55
|
+
delegate :write
|
56
|
+
delegate :read
|
57
|
+
delegate :mtime
|
58
|
+
delegate :mtime=
|
59
|
+
delegate :entries
|
60
|
+
delegate :glob
|
61
|
+
delegate :atime
|
62
|
+
delegate :atime=
|
63
|
+
delegate :get_umask
|
64
|
+
delegate :set_umask
|
65
|
+
delegate :mode
|
66
|
+
delegate :chmod
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def invoke_backend(mth, *args)
|
72
|
+
args << self if args.empty?
|
73
|
+
self.class.send :invoke_backend, mth, *args
|
74
|
+
end
|
75
|
+
|
76
|
+
class << self
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def invoke_backend(mth, *args)
|
81
|
+
Backend.instance.send mth, *args
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
require 'rubypath/backend/mock'
|
86
|
+
require 'rubypath/backend/sys'
|
87
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Path
|
2
|
+
# @!group Comparison
|
3
|
+
|
4
|
+
# Compare path to given object. If object is a string, Path or #{Path.like?}
|
5
|
+
# they will be compared using the string paths. Otherwise they are assumed
|
6
|
+
# as not equal.
|
7
|
+
#
|
8
|
+
# @param other [Object] Object to compare path with.
|
9
|
+
# @return [Boolean] True if object represents same path.
|
10
|
+
#
|
11
|
+
def eql?(other)
|
12
|
+
case other
|
13
|
+
when String
|
14
|
+
internal_path.eql? other
|
15
|
+
when Path
|
16
|
+
internal_path.eql? other.path
|
17
|
+
else
|
18
|
+
Path.new(other).eql?(self) if Path.like? other
|
19
|
+
end
|
20
|
+
end
|
21
|
+
alias_method :==, :eql?
|
22
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
class Path
|
2
|
+
|
3
|
+
class << self
|
4
|
+
# @!group Construction
|
5
|
+
|
6
|
+
# Create new {Path}.
|
7
|
+
#
|
8
|
+
# If single argument is a path object it will be returned and no new one
|
9
|
+
# will be created. If not arguments are given {Path::EMPTY} will be
|
10
|
+
# returned.
|
11
|
+
#
|
12
|
+
# @see #initialize
|
13
|
+
#
|
14
|
+
def new(*args)
|
15
|
+
args.flatten!
|
16
|
+
return Path::EMPTY if args.empty?
|
17
|
+
return args.first if args.size == 1 && args.first.is_a?(self)
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
# Check if given object is like a path.
|
22
|
+
#
|
23
|
+
# An object is like a path if
|
24
|
+
# 1. It is a {Path} object.
|
25
|
+
# 2. It is a string.
|
26
|
+
# 3. It responds to {#to_path} and {#to_path} returns a string.
|
27
|
+
# 4. It responds to {#path} and {#path} returns a string.
|
28
|
+
#
|
29
|
+
# If no rule matches it is not considered to be like a path.
|
30
|
+
#
|
31
|
+
# @return [Boolean] True if object is path like, false otherwise.
|
32
|
+
#
|
33
|
+
def like?(obj)
|
34
|
+
return true if obj.is_a?(self)
|
35
|
+
return true if obj.is_a?(String)
|
36
|
+
return true if obj.respond_to?(:to_path) && obj.to_path.is_a?(String)
|
37
|
+
return true if obj.respond_to?(:path) && obj.path.is_a?(String)
|
38
|
+
false
|
39
|
+
end
|
40
|
+
|
41
|
+
# Convert given object to path string using {::Path.like?} rules.
|
42
|
+
#
|
43
|
+
# @note Should not be used directly.
|
44
|
+
#
|
45
|
+
# @return [String]
|
46
|
+
# @raise [ArgumentError] If given object is not {::Path.like?}.
|
47
|
+
# @see ::Path.like?
|
48
|
+
#
|
49
|
+
def like_path(obj)
|
50
|
+
case obj
|
51
|
+
when String
|
52
|
+
return obj
|
53
|
+
else
|
54
|
+
[:to_path, :path, :to_str, :to_s].each do |mth|
|
55
|
+
if obj.respond_to?(mth) && obj.send(mth).is_a?(String)
|
56
|
+
return obj.send(mth)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
raise ArgumentError.new \
|
62
|
+
"Argument #{obj.inspect} cannot be converted to path string."
|
63
|
+
end
|
64
|
+
|
65
|
+
# Return system file path separator.
|
66
|
+
#
|
67
|
+
# @return [String] File separator.
|
68
|
+
# @see ::File::SEPARATOR
|
69
|
+
#
|
70
|
+
def separator
|
71
|
+
::File::SEPARATOR
|
72
|
+
end
|
73
|
+
|
74
|
+
# Allow class object to be used as a bock.
|
75
|
+
#
|
76
|
+
# @example
|
77
|
+
# %w(path/to/fileA path/to/fileB).map(&Path)
|
78
|
+
#
|
79
|
+
def to_proc
|
80
|
+
proc {|*args| Path.new(*args) }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# @!group Construction
|
85
|
+
|
86
|
+
# Initialize new {Path} object.
|
87
|
+
#
|
88
|
+
# Given arguments will be converted to String using `#to_path`, `#path` or
|
89
|
+
# `#to_s` in this order if they return a String object.
|
90
|
+
#
|
91
|
+
# @overload initialize([[String, #to_path, #path, #to_s], ...]
|
92
|
+
#
|
93
|
+
def initialize(*args)
|
94
|
+
parts = args.flatten
|
95
|
+
@path = if parts.size > 1
|
96
|
+
::File.join(*parts.map{|p| Path.like_path p })
|
97
|
+
elsif parts.size == 1
|
98
|
+
Path.like_path(parts.first).dup
|
99
|
+
else
|
100
|
+
''
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Empty path.
|
105
|
+
#
|
106
|
+
# @return [Path] Empty path.
|
107
|
+
#
|
108
|
+
EMPTY = Path.new('')
|
109
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
class Path
|
2
|
+
class << self
|
3
|
+
|
4
|
+
# Returns the current working directory.
|
5
|
+
#
|
6
|
+
# @return [Path] Current working directory.
|
7
|
+
# @see ::Dir.getwd
|
8
|
+
#
|
9
|
+
def getwd
|
10
|
+
new Backend.instance.getwd
|
11
|
+
end
|
12
|
+
|
13
|
+
def glob(pattern, flags = ::File::FNM_EXTGLOB)
|
14
|
+
if block_given?
|
15
|
+
Backend.instance.glob(pattern, flags) {|path| yield Path path }
|
16
|
+
else
|
17
|
+
Backend.instance.glob(pattern, flags).map(&Path)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Create directory.
|
23
|
+
#
|
24
|
+
# Given arguments will be joined with current path before directory is
|
25
|
+
# created.
|
26
|
+
#
|
27
|
+
# @raise [Errno::ENOENT] If parent directory could not created.
|
28
|
+
# @return [Path] Path to created directory.
|
29
|
+
# @see #mkpath
|
30
|
+
#
|
31
|
+
def mkdir(*args)
|
32
|
+
with_path(*args) do |path|
|
33
|
+
Backend.instance.mkdir path
|
34
|
+
Path path
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Create directory and all missing parent directories.
|
39
|
+
#
|
40
|
+
# Given arguments will be joined with current path before directories
|
41
|
+
# are created.
|
42
|
+
#
|
43
|
+
# @return [Path] Path to created directory.
|
44
|
+
# @see #mkdir
|
45
|
+
# @see ::FileUtils.mkdir_p
|
46
|
+
#
|
47
|
+
def mkpath(*args)
|
48
|
+
with_path(*args) do |path|
|
49
|
+
Backend.instance.mkpath path
|
50
|
+
Path path
|
51
|
+
end
|
52
|
+
end
|
53
|
+
alias_method :mkdir_p, :mkpath
|
54
|
+
|
55
|
+
# Return list of entries in directory. That includes special directories
|
56
|
+
# (`.`, `..`).
|
57
|
+
#
|
58
|
+
# Given arguments will be joined before children are listed for directory.
|
59
|
+
#
|
60
|
+
# @return [Array<Path>] Entries in directory.
|
61
|
+
#
|
62
|
+
def entries(*args)
|
63
|
+
invoke_backend(:entries, internal_path).map(&Path)
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
def glob(pattern, flags = ::File::FNM_EXTGLOB)
|
68
|
+
Path.glob ::File.join(escaped_glob_path, pattern), flags
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def escaped_glob_path
|
74
|
+
internal_path.gsub(/[\[\]\*\?\{\}]/, '\\\\\0')
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
class Path
|
2
|
+
# @!group File Extensions
|
3
|
+
|
4
|
+
# Return list of all file extensions.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# Path.new('/path/to/template.de.html.erb').extensions
|
8
|
+
# #=> ['de', 'html', 'erb']
|
9
|
+
#
|
10
|
+
# @return [Array<String>] List of file extensions.
|
11
|
+
#
|
12
|
+
def extensions
|
13
|
+
if dotfile?
|
14
|
+
name.split('.')[2..-1]
|
15
|
+
else
|
16
|
+
name.split('.')[1..-1]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
alias_method :exts, :extensions
|
20
|
+
|
21
|
+
# Return last file extension.
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# Path.new('/path/to/template.de.html.erb').extension
|
25
|
+
# #=> 'erb'
|
26
|
+
#
|
27
|
+
# @return [String] Last file extensions.
|
28
|
+
#
|
29
|
+
def extension
|
30
|
+
extensions.last
|
31
|
+
end
|
32
|
+
alias_method :ext, :extension
|
33
|
+
|
34
|
+
# Return last file extension include dot character.
|
35
|
+
#
|
36
|
+
# @return [String] Ext name.
|
37
|
+
# @see ::File.extname
|
38
|
+
#
|
39
|
+
def extname
|
40
|
+
::File.extname name
|
41
|
+
end
|
42
|
+
|
43
|
+
# Return the file name without any extensions.
|
44
|
+
#
|
45
|
+
# @example
|
46
|
+
# Path("template.de.html.slim").pure_name
|
47
|
+
# #=> "template"
|
48
|
+
#
|
49
|
+
# @example
|
50
|
+
# Path("~/.gitconfig").pure_name
|
51
|
+
# #=> ".gitconfig"
|
52
|
+
#
|
53
|
+
# @return [String] File name without extensions.
|
54
|
+
#
|
55
|
+
def pure_name
|
56
|
+
if dotfile?
|
57
|
+
name.split('.', 3)[0..1].join('.')
|
58
|
+
else
|
59
|
+
name.split('.', 2)[0]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Replace file extensions with given new ones or by a given
|
64
|
+
# translation map.
|
65
|
+
#
|
66
|
+
# @overload replace_extensions(exts)
|
67
|
+
# Replace all extensions with given new ones. Number of given extensions
|
68
|
+
# does not need to match number of existing extensions.
|
69
|
+
#
|
70
|
+
# @example
|
71
|
+
# Path('file.de.txt').replace_extensions(%w(en html))
|
72
|
+
# #=> <Path "file.en.html">
|
73
|
+
#
|
74
|
+
# @example
|
75
|
+
# Path('file.de.mobile.html.haml').replace_extensions(%w(int txt))
|
76
|
+
# #=> <Path "file.int.txt">
|
77
|
+
#
|
78
|
+
# @param exts [Array<String>] New extensions.
|
79
|
+
#
|
80
|
+
# @overload replace_extensions(ext, [ext, [..]])
|
81
|
+
# Replace all extensions with given new ones. Number of given extensions
|
82
|
+
# does not need to match number of existing extensions.
|
83
|
+
#
|
84
|
+
# @example
|
85
|
+
# Path('file.de.txt').replace_extensions('en', 'html')
|
86
|
+
# #=> <Path "file.en.html">
|
87
|
+
#
|
88
|
+
# @example
|
89
|
+
# Path('file.de.mobile.html.haml').replace_extensions('en', 'html')
|
90
|
+
# #=> <Path "file.en.html">
|
91
|
+
#
|
92
|
+
# @example
|
93
|
+
# Path('file.de.txt').replace_extensions('html')
|
94
|
+
# #=> <Path "file.html">
|
95
|
+
#
|
96
|
+
# @param ext [String] New extensions.
|
97
|
+
#
|
98
|
+
# @overload replace_extensions(map)
|
99
|
+
# Replace all matching extensions.
|
100
|
+
#
|
101
|
+
# @example
|
102
|
+
# Path('file.de.html.haml').replace_extensions('de' => 'en', 'haml' => 'slim')
|
103
|
+
# #=> <Path "file.en.html.slim">
|
104
|
+
#
|
105
|
+
# @param map [Hash<String, String>] Translation map as hash.
|
106
|
+
#
|
107
|
+
# @return [Path] Path to new filename.
|
108
|
+
#
|
109
|
+
def replace_extensions(*args)
|
110
|
+
args.flatten!
|
111
|
+
extensions = self.extensions
|
112
|
+
|
113
|
+
if (replace = (args.last.is_a?(Hash) ? args.pop : nil))
|
114
|
+
if args.empty?
|
115
|
+
extensions.map! do |ext|
|
116
|
+
replace[ext] ? replace[ext].to_s : ext
|
117
|
+
end
|
118
|
+
else
|
119
|
+
raise ArgumentError.new 'Cannot replace extensions with array ' \
|
120
|
+
'and hash at the same time.'
|
121
|
+
end
|
122
|
+
else
|
123
|
+
extensions = args.map(&:to_s)
|
124
|
+
end
|
125
|
+
|
126
|
+
if extensions == self.extensions
|
127
|
+
self
|
128
|
+
else
|
129
|
+
if only_filename?
|
130
|
+
Path "#{pure_name}.#{extensions.join('.')}"
|
131
|
+
else
|
132
|
+
dirname.join "#{pure_name}.#{extensions.join('.')}"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Replace last extension with one or multiple new extensions.
|
138
|
+
#
|
139
|
+
# @example
|
140
|
+
# Path('file.de.txt').replace_extension('html')
|
141
|
+
# #=> <Path "file.de.html">
|
142
|
+
#
|
143
|
+
# @example
|
144
|
+
# Path('file.de.txt').replace_extension('html', 'erb')
|
145
|
+
# #=> <Path "file.de.html.erb">
|
146
|
+
#
|
147
|
+
# @return [Path] Path to new filename.
|
148
|
+
#
|
149
|
+
def replace_extension(*args)
|
150
|
+
extensions = self.extensions
|
151
|
+
extensions.pop
|
152
|
+
extensions += args.flatten
|
153
|
+
|
154
|
+
replace_extensions extensions
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|