Pathname
Pathname
Pathname은 파일시스템의 파일이나 디렉터리의 이름을 객체로 다루는 클래스예요. 중요한 건 파일 그 자체가 아니라 이름이라는 점이에요.
Pathname은 파일 경로 정보를 표준 Ruby가 제공하는 것보다 더 깔끔하게 다루는 게 목표예요. 아래 예제들이 그 차이를 보여줘요.
출처: Ruby 4.0 API
본문
Pathname이 나타내는 경로는 운영체제(Unix, Windows 등)에 따라 달라요. 이 라이브러리는 로컬 OS의 경로를 다루며, 비-Unix 경로는 실험적으로 지원돼요.
Pathname은 상대 경로일 수도 있고 절대 경로일 수도 있어요. 파일을 실제로 참조하려고 시도하기 전까지는 파일이 존재하는지조차 중요하지 않죠.
Pathname은 불변(immutable)이에요. 파괴적 업데이트를 하는 메서드가 없어요.
File, FileTest의 모든 기능과 Dir, FileUtils의 일부 기능이 예상되는 방식 그대로 포함돼 있어요. 사실상 이 모든 것들(그리고 그 이상)을 위한 파사드(facade)예요.
Examples
Example 1: Pathname 사용하기
require 'pathname'
pn = Pathname.new("/usr/bin/ruby")
size = pn.size # 27662
isdir = pn.directory? # false
dir = pn.dirname # Pathname:/usr/bin
base = pn.basename # Pathname:ruby
dir, base = pn.split # [Pathname:/usr/bin, Pathname:ruby]
data = pn.read
pn.open { |f| _ }
pn.each_line { |line| _ }
Example 2: 표준 Ruby 사용하기
pn = "/usr/bin/ruby"
size = File.size(pn) # 27662
isdir = File.directory?(pn) # false
dir = File.dirname(pn) # "/usr/bin"
base = File.basename(pn) # "ruby"
dir, base = File.split(pn) # ["/usr/bin", "ruby"]
data = File.read(pn)
File.open(pn) { |f| _ }
File.foreach(pn) { |line| _ }
Example 3: 특별한 기능들
p1 = Pathname.new("/usr/lib") # Pathname:/usr/lib
p2 = p1 + "ruby/1.8" # Pathname:/usr/lib/ruby/1.8
p3 = p1.parent # Pathname:/usr
p4 = p2.relative_path_from(p3) # Pathname:lib/ruby/1.8
pwd = Pathname.pwd # Pathname:/home/gavin
pwd.absolute? # true
p5 = Pathname.new "." # Pathname:.
p5 = p5 + "music/../articles" # Pathname:music/../articles
p5.cleanpath # Pathname:articles
p5.realpath # Pathname:/home/gavin/articles
p5.children # [Pathname:/home/gavin/articles/linux, ...]
기능 구성(Breakdown of functionality)
핵심 메서드(Core methods)
이 메서드들은 사실상 String을 다루는 것들이에요. 경로가 결국 문자열이니까요. 그중 mountpoint?, children, each_child, realdirpath, realpath를 제외하면 어느 것도 파일시스템에 접근하지 않아요.
+joinparentroot?absolute?relative?relative_path_fromeach_filenamecleanpathrealpathrealdirpathchildreneach_childmountpoint?
파일 상태 술어 메서드(File status predicate methods)
이 메서드들은 FileTest를 위한 파사드예요.
blockdev?chardev?directory?executable?executable_real?exist?file?grpowned?owned?pipe?readable?world_readable?readable_real?setgid?setuid?sizesize?socket?sticky?symlink?writable?world_writable?writable_real?zero?
파일 속성·조작 메서드(File property and manipulation methods)
이 메서드들은 File을 위한 파사드예요.
each_line(*args, &block)read(*args)binread(*args)readlines(*args)sysopen(*args)write(*args)binwrite(*args)atimebirthtimectimemtimechmod(mode)lchmod(mode)chown(owner, group)lchown(owner, group)fnmatch(pattern, *args)fnmatch?(pattern, *args)ftypemake_link(old)open(*args, &block)readlinkrename(to)statlstatmake_symlink(old)truncate(length)utime(atime, mtime)lutime(atime, mtime)basename(*args)dirnameextnameexpand_path(*args)split
디렉터리 메서드(Directory methods)
이 메서드들은 Dir을 위한 파사드예요.
Pathname.glob(*args)Pathname.getwd/Pathname.pwdrmdirentrieseach_entry(&block)mkdir(*args)opendir(*args)
유틸리티(Utilities)
이 메서드들은 Find, FileUtils 등을 섞어 쓴 것이에요.
find(&block)mkpathrmtreeunlink/delete
메서드 문서에 대해
위 구성을 보듯이, Pathname의 대부분 메서드는 파사드예요. 이 메서드들의 문서는 보통 "See FileTest.writable?"처럼 되어 있어요. 원래 메서드를 이미 잘 알 테니까, 더 자세한 정보는 원래 메서드의 문서(예: ri)에서 확인하면 돼요. 어떤 경우엔 간단한 설명이 따라붙어요.
Constants
ABSOLUTE_PATH
절대 경로와 일치하는 정규표현식이에요.
SEPARATOR_LIST
구분자 목록 문자열이에요.
SEPARATOR_PAT
구분자와 일치하는 정규표현식이에요.
VERSION
버전 문자열이에요.
Public Class Methods
getwd()
Dir.getwd를 참고하세요. 현재 작업 디렉터리를 Pathname으로 돌려줘요.
glob(*args, **kwargs) { |pathname| ... }
Dir.glob을 참고하세요. Pathname 객체를 돌려주거나 yield 해요.
mktmpdir() { |dir| ... }
임시 디렉터리를 만들고 반환된 경로를 Pathname 객체로 감싸요. 이 메서드를 쓰려면 require 'pathname'이 필요해요. Dir.mktmpdir을 참고하세요.
new(path)
주어진 String(또는 String-유사 객체)에서 Pathname 객체를 만들어요. path에 NUL 문자(\0)가 있으면 ArgumentError가 발생해요.
pwd()
Public Instance Methods
+(other)
pathname 조각을 self에 덧붙여 새 Pathname 객체를 만들어요. other는 self에 상대적인 경로로 간주되므로, other가 절대 경로라면 other만으로 새 Pathname 객체가 만들어져요.
p1 = Pathname.new("/usr") # Pathname:/usr
p2 = p1 + "bin/ruby" # Pathname:/usr/bin/ruby
p3 = p1 + "/etc/passwd" # Pathname:/etc/passwd
# / is aliased to +.
p4 = p1 / "bin/ruby" # Pathname:/usr/bin/ruby
p5 = p1 / "/etc/passwd" # Pathname:/etc/passwd
이 메서드는 파일시스템에 접근하지 않아요. 순수 문자열 조작이에요.
/(other)
+의 별칭이에요.
<=>(p1)
pathname을 위한 대소문자 구분(sensitive) 비교 연산자예요.
Pathname.new('/usr') <=> Pathname.new('/usr/bin')
#=> -1
Pathname.new('/usr/bin') <=> Pathname.new('/usr/bin')
#=> 0
Pathname.new('/usr/bin') <=> Pathname.new('/USR/BIN')
#=> 1
왼쪽 인자가 오른쪽 인자에 상대적인 값에 따라 -1, 0, 1을 돌려줘요. 인자들을 비교할 수 없으면 nil을 돌려줘요.
==(other)
이 pathname을 other와 비교해요. 비교는 문자열 기반이에요. 서로 다른 두 경로(foo.txt와 ./foo.txt)가 같은 파일을 가리킬 수 있다는 점을 알아 두세요.
===(other)
absolute?()
경로가 절대 경로인지 검사하는 술어 메서드예요. pathname이 슬래시로 시작하면 true를 돌려줘요.
p = Pathname.new('/im/sure')
p.absolute?
#=> true
p = Pathname.new('not/so/sure')
p.absolute?
#=> false
ascend() { |self| ... }
주어진 경로의 각 요소에 대해 오름차순으로 새 Pathname 객체를 만들고 yield 해요.
Pathname.new('/path/to/some/file.rb').ascend {|v| p v}
#<Pathname:/path/to/some/file.rb>
#<Pathname:/path/to/some>
#<Pathname:/path/to>
#<Pathname:/path>
#<Pathname:/>
Pathname.new('path/to/some/file.rb').ascend {|v| p v}
#<Pathname:path/to/some/file.rb>
#<Pathname:path/to/some>
#<Pathname:path/to>
#<Pathname:path>
블록이 없으면 Enumerator를 돌려줘요.
enum = Pathname.new("/usr/bin/ruby").ascend
# ... do stuff ...
enum.each { |e| ... }
# yields Pathnames /usr/bin/ruby, /usr/bin, /usr, and /.
파일시스템에 접근하지 않아요.
atime()
File.atime을 참고하세요. 마지막 접근 시간을 돌려줘요.
basename(...)
File.basename을 참고하세요. 경로의 마지막 구성요소를 돌려줘요.
binread(...)
File.binread를 참고하세요. 파일의 모든 바이트를 돌려주거나, 지정하면 처음 N 바이트를 돌려줘요.
binwrite(...)
이진 모드로 파일을 열어 내용을 써요. File.binwrite를 참고하세요.
birthtime()
파일의 birth time을 돌려줘요. 플랫폼에 birthtime이 없으면 NotImplementedError를 발생시켜요. File.birthtime을 참고하세요.
blockdev?()
FileTest.blockdev?를 참고하세요.
chardev?()
FileTest.chardev?를 참고하세요.
children(with_directory=true)
디렉터리의 자식들(파일과 하위 디렉터리, 비재귀적)을 Pathname 객체 배열로 돌려줘요. 기본적으로 돌려받는 pathname은 파일에 접근할 충분한 정보를 가져요. with_directory를 false로 설정하면 돌려받는 pathname은 파일 이름만 담아요.
pn = Pathname("/usr/lib/ruby/1.8")
pn.children
# -> [ Pathname:/usr/lib/ruby/1.8/English.rb,
Pathname:/usr/lib/ruby/1.8/Env.rb,
Pathname:/usr/lib/ruby/1.8/abbrev.rb, ... ]
pn.children(false)
# -> [ Pathname:English.rb, Pathname:Env.rb, Pathname:abbrev.rb, ... ]
결과에 디렉터리의 .과 .. 항목은 절대 포함되지 않아요. 그것들은 자식이 아니니까요.
chmod(mode)
File.chmod을 참고하세요. 권한을 바꿔요.
chown(owner, group)
File.chown을 참고하세요. 파일의 소유자와 그룹을 바꿔요.
cleanpath(consider_symlink=false)
연속된 슬래시와 쓸모없는 점을 제거한 self의 정리된 pathname을 돌려줘요. 파일시스템에 접근하지 않아요. consider_symlink이 true이면 심볼릭 링크 연결을 깨지 않도록 더 보수적인 알고리즘을 사용해요. 이 경우 필요 이상으로 많은 .. 항목이 남을 수 있지만, 파일시스템에 접근하지 않는 한 피할 수 없어요. Pathname#realpath를 참고하세요.
ctime()
File.ctime을 참고하세요. 마지막(디렉터리 항목, 파일이 아닌) 변경 시간을 돌려줘요.
delete()
unlink의 별칭이에요.
descend() { |v| ... }
주어진 경로의 각 요소에 대해 내림차순으로 새 Pathname 객체를 만들고 yield 해요.
Pathname.new('/path/to/some/file.rb').descend {|v| p v}
#<Pathname:/>
#<Pathname:/path>
#<Pathname:/path/to>
#<Pathname:/path/to/some>
#<Pathname:/path/to/some/file.rb>
Pathname.new('path/to/some/file.rb').descend {|v| p v}
#<Pathname:path>
#<Pathname:path/to>
#<Pathname:path/to/some>
#<Pathname:path/to/some/file.rb>
블록이 없으면 Enumerator를 돌려줘요.
enum = Pathname.new("/usr/bin/ruby").descend
# ... do stuff ...
enum.each { |e| ... }
# yields Pathnames /, /usr, /usr/bin, and /usr/bin/ruby.
파일시스템에 접근하지 않아요.
directory?()
FileTest.directory?를 참고하세요.
dirname()
File.dirname을 참고하세요. 경로의 마지막 구성요소를 뺀 나머지를 돌려줘요.
each_child(with_directory=true, &b)
디렉터리의 자식들(파일과 하위 디렉터리, 비재귀적)을 순회해요. 각 자식에 대해 Pathname 객체를 yield 해요. 기본적으로 yield 되는 pathname은 파일에 접근할 충분한 정보를 가져요. with_directory를 false로 설정하면 돌려받는 pathname은 파일 이름만 담아요.
Pathname("/usr/local").each_child {|f| p f }
#=> #<Pathname:/usr/local/share>
# #<Pathname:/usr/local/bin>
# #<Pathname:/usr/local/games>
# #<Pathname:/usr/local/lib>
# #<Pathname:/usr/local/include>
# #<Pathname:/usr/local/sbin>
# #<Pathname:/usr/local/src>
# #<Pathname:/usr/local/man>
Pathname("/usr/local").each_child(false) {|f| p f }
#=> #<Pathname:share>
# #<Pathname:bin>
# #<Pathname:games>
# #<Pathname:lib>
# #<Pathname:include>
# #<Pathname:sbin>
# #<Pathname:src>
# #<Pathname:man>
결과에 .과 .. 항목은 절대 포함되지 않아요. Pathname#children을 참고하세요.
each_entry() { |pathname| ... }
디렉터리의 항목(파일과 하위 디렉터리)을 순회해요. 각 항목에 대해 Pathname 객체를 yield 해요. 이 메서드는 1.8.1부터 있었어요.
each_filename() { |filename| ... }
경로의 각 구성요소를 순회해요.
Pathname.new("/usr/bin/ruby").each_filename {|filename| ... }
# yields "usr", "bin", and "ruby".
블록이 없으면 Enumerator를 돌려줘요.
enum = Pathname.new("/usr/bin/ruby").each_filename
# ... do stuff ...
enum.each { |e| ... }
# yields "usr", "bin", and "ruby".
each_line(...) { |line| ... }
파일의 줄을 순회해요. 각 줄에 대해 String 객체를 yield 해요. 1.8.1부터 있었어요.
empty?()
파일이 비어 있는지 검사해요. Dir#empty?와 FileTest.empty?를 참고하세요.
entries()
디렉터리의 항목(파일과 하위 디렉터리)을 각각 Pathname 객체로 돌려줘요.
eql?(other)
executable?()
FileTest.executable?를 참고하세요.
executable_real?()
FileTest.executable_real?을 참고하세요.
exist?()
FileTest.exist?를 참고하세요.
expand_path(...)
File.expand_path를 참고하세요.
extname()
File.extname을 참고하세요. 파일의 확장자를 돌려줘요.
file?()
FileTest.file?를 참고하세요.
find(ignore_error: true) { |pathname| ... }
디렉터리 트리를 깊이 우선 방식으로 순회하며, "this" 디렉터리 아래의 각 파일에 대해 Pathname을 yield 해요. 이 메서드를 쓰려면 require 'pathname'이 필요해요. 블록이 없으면 Enumerator를 돌려줘요. 표준 라이브러리 모듈 Find로 구현되어 있으므로, Find.prune으로 순회를 제어할 수 있어요. self가 .이면 yield 되는 pathname은 ./가 아니라 현재 디렉터리의 파일 이름으로 시작해요. Find.find를 참고하세요.
fnmatch(pattern, ...)
File.fnmatch를 참고하세요. receiver가 주어진 패턴과 일치하면 true를 돌려줘요.
fnmatch?(pattern, ...)
File.fnmatch?를 참고하세요(fnmatch와 같음).
freeze()
self를 동결해요. 슈퍼클래스 메서드 Object#freeze를 호출해요.
ftype()
File.ftype을 참고하세요. 파일의 "타입"("file", "directory" 등)을 돌려줘요.
glob(*args, **kwargs) { |pathname| ... }
Pathname 객체를 돌려주거나 yield 해요.
Pathname("ruby-2.4.2").glob("R*.md")
#=> [#<Pathname:ruby-2.4.2/README.md>, #<Pathname:ruby-2.4.2/README.ja.md>]
Dir.glob을 참고하세요. 이 메서드는 Dir.glob의 base 키워드 인자를 사용해요.
grpowned?()
FileTest.grpowned?를 참고하세요.
join(*args)
주어진 pathname들을 self에 이어붙여 새 Pathname 객체를 만들어요. Pathname#+를 사용해 self와 모든 인자를 순차적으로 덧붙이는 것과 사실상 같아요.
path0 = Pathname.new("/usr") # Pathname:/usr
path0 = path0.join("bin/ruby") # Pathname:/usr/bin/ruby
# is the same as
path1 = Pathname.new("/usr") + "bin/ruby" # Pathname:/usr/bin/ruby
path0 == path1
#=> true
lchmod(mode)
File.lchmod을 참고하세요.
lchown(owner, group)
File.lchown을 참고하세요.
lstat()
File.lstat을 참고하세요.
lutime(atime, mtime)
파일의 접근·수정 시간을 갱신해요. Pathname#utime와 같지만 심볼릭 링크를 따라가지 않아요. File.lutime을 참고하세요.
make_link(old)
File.link을 참고하세요. 하드 링크를 만들어요.
make_symlink(old)
File.symlink을 참고하세요. 심볼릭 링크를 만들어요.
mkdir(...)
Dir.mkdir을 참고하세요. 참조하는 디렉터리를 만들어요.
mkpath(mode: nil)
아직 존재하지 않는 중간 디렉터리를 포함해 전체 경로를 만들어요. FileUtils.mkpath와 FileUtils.mkdir_p를 참고하세요.
mountpoint?()
self가 마운트포인트를 가리키면 true를 돌려줘요.
mtime()
File.mtime을 참고하세요. 마지막 수정 시간을 돌려줘요.
open(...) { |file| ... }
File.open을 참고하세요. 읽기나 쓰기용으로 파일을 열어요.
opendir() { |dir| ... }
Dir.open을 참고하세요.
owned?()
FileTest.owned?를 참고하세요.
parent()
부모 디렉터리를 돌려줘요. self + '..'와 같아요.
pipe?()
FileTest.pipe?를 참고하세요.
read(...)
File.read을 참고하세요. 파일의 모든 데이터를 돌려주거나, 지정하면 처음 N 바이트를 돌려줘요.
readable?()
FileTest.readable?을 참고하세요.
readable_real?()
FileTest.readable_real?을 참고하세요.
readlines(...)
File.readlines을 참고하세요. 파일의 모든 줄을 돌려줘요.
readlink()
File.readlink을 참고하세요. 심볼릭 링크를 읽어요.
realdirpath(...)
실제 파일시스템에서 self의 실제(절대) pathname을 돌려줘요. 심볼릭 링크나 쓸모없는 점(.., .)을 포함하지 않아요. 실제 pathname의 마지막 구성요소는 존재하지 않아도 돼요.
realpath(...)
실제 파일시스템에서 self의 실제(절대) pathname을 돌려줘요. 심볼릭 링크나 쓸모없는 점(.., .)을 포함하지 않아요. 이 메서드를 호출할 때 pathname의 모든 구성요소가 존재해야 해요.
relative?()
Pathname#absolute?의 반대예요. pathname이 슬래시로 시작하면 false를 돌려줘요.
p = Pathname.new('/im/sure')
p.relative?
#=> false
p = Pathname.new('not/so/sure')
p.relative?
#=> true
relative_path_from(base_directory)
주어진 base_directory로부터 receiver까지의 상대 경로를 돌려줘요. self가 절대 경로면 base_directory도 절대 경로여야 해요. self가 상대 경로면 base_directory도 상대 경로여야 해요. 이 메서드는 파일시스템에 접근하지 않아요. 심볼릭 링크가 없다고 가정해요. 상대 경로를 찾을 수 없으면 ArgumentError가 발생해요. 이 메서드는 사용 중인 파일시스템의 대소문자 구분이 운영체제 기본값과 다른 상황은 처리하지 않는다는 점에 유의하세요.
rename(to)
File.rename을 참고하세요. 파일 이름을 바꿔요.
rmdir()
Dir.rmdir을 참고하세요. 참조하는 디렉터리를 제거해요.
rmtree(noop: nil, verbose: nil, secure: nil)
디렉터리 아래의 모든 디렉터리를 포함해 재귀적으로 삭제해요. 이 메서드를 쓰려면 require 'pathname'이 필요해요. FileUtils.rm_rf를 참고하세요.
root?()
루트 디렉터리 술어 메서드예요. pathname이 연속된 슬래시로 구성돼 있으면 true를 돌려줘요. 파일시스템에 접근하지 않아요. 그래서 /usr/.. 같은 루트를 가리키는 어떤 pathname에서는 false를 돌려줄 수 있어요.
setgid?()
FileTest.setgid?를 참고하세요.
setuid?()
FileTest.setuid?를 참고하세요.
size()
FileTest.size를 참고하세요.
size?()
FileTest.size?를 참고하세요.
socket?()
FileTest.socket?를 참고하세요.
split()
File.split을 참고하세요. dirname과 basename을 Array로 돌려줘요.
stat()
File.stat을 참고하세요. File::Stat 객체를 돌려줘요.
sticky?()
FileTest.sticky?를 참고하세요.
sub(*args)
String#sub로 치환된 pathname을 돌려줘요.
path1 = Pathname.new('/usr/bin/perl')
path1.sub('perl', 'ruby')
#=> #<Pathname:/usr/bin/ruby>
sub_ext(repl)
basename에 repl을 접미사로 덧붙인 pathname을 돌려줘요. self에 확장자 부분이 없으면 repl이 그대로 덧붙여져요.
Pathname.new('/usr/bin/shutdown').sub_ext('.rb')
#=> #<Pathname:/usr/bin/shutdown.rb>
symlink?()
FileTest.symlink?을 참고하세요.
sysopen(...)
File.sysopen을 참고하세요.
to_path()
Pathname 객체를 File.open 등에서 사용할 수 있도록 구현된 메서드예요.
to_s()
경로를 String으로 돌려줘요.
truncate(length)
File.truncate을 참고하세요. 파일을 length 바이트로 잘라요.
unlink()
필요에 따라 File.unlink이나 Dir.unlink을 사용해 파일이나 디렉터리를 제거해요.
utime(atime, mtime)
File.utime을 참고하세요. 접근·수정 시간을 갱신해요.
world_readable?()
FileTest.world_readable?을 참고하세요.
world_writable?()
FileTest.world_writable?을 참고하세요.
writable?()
FileTest.writable?을 참고하세요.
writable_real?()
FileTest.writable_real?을 참고하세요.
write(...)
파일에 내용을 써요. File.write를 참고하세요.
zero?()
FileTest.zero?를 참고하세요.