콘텐츠 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11

공식 Ruby FAQ

If you wish to report errors or suggest improvements for this FAQ, please go to our GitHub repository and open an issue or pull request.

내장 라이브러리

instance_methods(false)는 무엇을 반환하나요?

인스턴스 메서드 instance_methods는 수신 클래스 또는 모듈의 인스턴스 메서드 이름이 포함된 배열을 반환합니다. 여기에는 슈퍼클래스와 모듈에 믹스인된 메서드가 포함됩니다.

instance_methods(false)instance_methods(nil)는 수신자에 정의된 메소드의 이름만 반환합니다.

난수 시드는 어떻게 작동하나요?

srand를 미리 호출하지 않고 rand가 호출되면, 루비의 의사 난수 생성기는 무엇보다도 OS에서 제공하는 엔트로피 소스를 사용하는 랜덤(에 가까운) 시드를 사용합니다(사용 가능한 경우). srand 를 사용하지 않는 프로그램을 연속적으로 실행하면 다른 난수 시퀀스가 생성됩니다.

테스트 목적으로, 상수 시드를 사용하여 srand를 호출하면 프로그램을 실행할 때마다 동일한 일련의 숫자로 예측 가능한 동작을 얻을 수 있습니다.

파일을 읽고 변경했지만 디스크의 파일은 변경되지 않았습니다.

File.open("example", "r+").readlines.each_with_index do |line, i|
  line[0,0] = "#{i+1}: "
end

이 프로그램은 example 파일에 줄 번호를 추가하지 않습니다. 파일의 내용을 읽 고 각 줄마다 줄 번호를 앞에 붙이기는 하지만 데이터를 다시 쓰지는 않습니다. 아래 코드는 파일을 _업데이트_합니다(업데이트를 시작하기 전에 백업을 하지 않기 때문에 다소 위험할 수 있습니다).

File.open("example", "r+") do |f|
  lines = f.readlines
  lines.each_with_index {|line, i| line[0,0] = "#{i+1}: " }
  f.rewind
  f.puts lines
end

파일을 처리하고 내용을 업데이트하려면 어떻게 해야 하나요?

명령줄 옵션 -i 또는 내장 변수 $-i를 사용하여 파일을 읽고 바꿀 수 있습니다.

파일에 줄 번호를 추가한 이전 질문의 코드는 이 기법을 사용하여 작성하는 것이 가장 좋습니다.

$ ruby -i -ne 'print "#$.: #$_"' example

원본 파일을 보존하려면 -i.bak을 사용하여 백업을 만드세요.

파일을 작성하고 복사했는데 복사본의 끝 부분이 손실된 것 같습니다.

이 코드는 제대로 작동하지 않습니다.

require "fileutils"

File.open("file", "w").puts "This is a file."
FileUtils.cp("file", "newfile")

I/O가 버퍼링되어 있기 때문에 file의 내용이 디스크에 기록되기 전에 복사되고 있습니다. newfile은 아마도 비어 있을 것입니다. 그러나 프로그램이 종료되면 버퍼가 플러시되고 파일에는 예상되는 콘텐츠가 있습니다.

복사하기 전에 ‘파일’이 닫혀 있는지 확인하면 문제가 발생하지 않습니다.

require "fileutils"

File.open("file", "w") {|f| f.puts "This is a file." }
FileUtils.cp("file", "newfile")

현재 입력 파일에서 줄 번호를 얻으려면 어떻게 해야 하나요?

파일에서 읽을 때 Ruby는 전역 변수 $.의 줄 번호 카운터를 증가시킵니다. 이 기능은 File 객체의 lineno 속성을 사용하여 사용할 수도 있습니다.

특수 상수 ARGF는 명령줄에 지정된 모든 입력 파일(파일이 없는 경우 표준 입력)을 읽는 데 사용할 수 있는 파일과 유사한 객체입니다. ARGF는 다음과 같은 코드에서 암시적으로 사용됩니다.

while gets
  print $_
end

이 경우 $.는 모든 입력 파일에서 읽은 누적 줄 수가 됩니다. 현재 파일에서 줄 번호를 가져오려면 다음 코드를 사용하세요.

ARGF.file.lineno

ARGF.file.path를 사용하여 현재 파일의 이름을 가져올 수도 있습니다.

프로그램 출력을 표시하기 위해 less를 사용하려면 어떻게 해야 하나요?

다음을 시도했지만 아무것도 나오지 않았습니다.

open("|less", "w").puts "abc"

프로그램이 즉시 종료되어서 less는 작성한 내용을 볼 기회를 얻지 못 하며 표시할 수도 없기 때문입니다. IO가 제대로 닫혔는지 확인하고 less가 끝날 때까지 기다리세요.

open("|less", "w") {|f| f.puts "abc" }

더 이상 참조되지 않는 File 객체는 어떻게 되나요?

더 이상 참조되지 않는 File 객체는 가비지 컬렉션 대상이 됩니다. File 객체가 가비지 컬랙션되면 파일은 자동으로 닫힙니다.

파일을 닫지 않으면 불안한 기분이 들어요.

파일을 닫는 데는 최소한 네 가지의 좋은 방법이 있습니다.

# (1)
f = File.open("file")
begin
  f.each {|line| print line }
ensure
  f.close
end

# (2)
File.open("file") do |f|
  f.each {|line| print line }
end

# (3)
File.foreach("file") {|line| print line }

# (4)
File.readlines("file").each {|line| print line }

수정 시간별로 파일을 정렬하려면 어떻게 해야 하나요?

Dir.glob("*").sort {|a, b| File.mtime(b) <=> File.mtime(a) }

이 방법은 작동하지만(시간 역순으로 목록을 반환), 비교할 때마다 운영 체제 에서 파일의 수정 시간을 가져오기 때문에 효율적이지 않습니다.

약간의 복잡성을 추가하면 더 효율적일 수 있습니다.

Dir.glob("*").map {|f| [File.mtime(f), f] }.
  sort {|a, b| b[0] <=> a[0] }.map(&:last)

파일에서 단어의 빈도를 계산하려면 어떻게 해야 하나요?

freq = Hash.new(0)
File.read("example").scan(/\w+/) {|word| freq[word] += 1 }
freq.keys.sort.each {|word| puts "#{word}: #{freq[word]}" }

결과:

and: 1
is: 3
line: 3
one: 1
this: 3
three: 1
two: 1

문자열을 알파벳 순서로 정렬하려면 어떻게 해야 하나요?

문자열을 ‘AAA’, ‘BBB’, …, ‘ZZZ’, ‘aaa’, ‘bbb’로 정렬하려는 경우 추가 구현없이 내장 비교를 사용하는 것으로 충분합니다.

대/소문자 구분을 무시하고 정렬하려면 정렬 블록에서 대/소문자 구분이 없는 문자열 버전을 비교합니다.

array = %w( z bB Bb bb Aa BB aA AA aa a A )
array.sort {|a, b| a.downcase <=> b.downcase }
  # => ["a", "A", "Aa", "aA", "AA", "aa", "bB", "Bb", "bb", "BB", "z"]

‘A’와 ‘a’가 함께 나오지만 ‘a’가 ‘A’보다 큰 것으로 간주되도록 정렬하려면 (즉, ‘Aa’가 ‘AA’ 뒤에 오지만 ‘AB’ 앞에 오도록) 이렇게 하세요.

array.sort {|a, b| (a.downcase <=> b.downcase).nonzero? || a <=> b }
  # => ["A", "a", "AA", "Aa", "aA", "aa", "BB", "Bb", "bB", "bb", "z"]

탭을 스페이스로 확장하려면 어떻게 해야 하나요?

확장할 문자열이 a인 경우 다음 중 하나를 사용할 수 있습니다.

1 while a.sub!(/(^[^\t]*)\t(\t*)/){$1+" "*(8-$1.size%8+8*$2.size)}
# 또는
1 while a.sub!(/\t(\t*)/){" "*(8-$~.begin(0)%8+8*$1.size)}
# 또는
a.gsub!(/([^\t]{8})|([^\t]*)\t/n){[$+].pack("A8")}

정규식에서 백슬래시를 이스케이프하려면 어떻게 해야 하나요?

Regexp.quote('\\')는 백슬래시를 이스케이프합니다.

subgsub를 사용하는 경우 더 까다로워집니다. 백슬래시를 각각 두 개로 바꾸기 위해 gsub(/\\/, '\\\\')를 작성한다고 가정해 보겠습니다. 두 번째 인수는 구문 분석에서 '\\'로 변환됩니다. 치환이 발생하면 정규식 엔진이 이를 '\'로 변환하므로 결과적으로 백슬래시 하나씩을 다른 백슬래시 하나로 대체하게 됩니다. 그래서 gsub(/\\/, '\\\\\\')로 작성해야 합니다!

그러나 \&는 매칭한 문자열을 포함한다는 사실을 사용하여 gsub(/\\/, '\&\&')라 적을 수도 있습니다.

gsub의 블록 형식, 즉 gsub(/\\/) { '\\\\' }를 사용하면 대체 문자열은 구문 전달 중에 한 번만 분석되며 결과는 사용자가 의도한 대로 나타납니다.

subsub!의 차이점은 무엇인가요?

sub에서는 수신자의 복사본이 생성되고 치환되어 반환됩니다.

sub!에서는 수신자가 변경되고 일치하는 항목이 발견되면 반환됩니다. 그렇지 않으면 nil이 반환됩니다.

수신자의 속성을 변경하는 sub!와 같은 메서드를 파괴적 메서드라고 합니다. 일반적으로 유사한 메서드가 두 개 있고 하나가 파괴적인 경우, 파괴적인 메서드에는 접미사 !가 붙습니다.

def foo(str)
  str.sub(/foo/, "baz")
end

obj = "foo"
foo(obj)  # => "baz"
obj       # => "foo"

def foo(str)
  str.sub!(/foo/, "baz")
end

foo(obj)  # => "baz"
obj       # => "baz"

\Z는 어디에 일치하나요?

문자열이 \n으로 끝나면 마지막 \n(줄 바꿈) 바로 앞에 \Z가 일치하고, 그렇지 않으면 문자열 끝에서 일치합니다.

threadfork의 차이점은 무엇인가요?

This section or parts of it might be out-dated or in need of confirmation.

Ruby 스레드는 인터프리터 내에서 구현되는 반면, fork는 운영 체제를 호출하여 별도로 실행되는 서브 프로세스를 생성합니다.

스레드와 fork에는 다음과 같은 특징이 있습니다.

  • fork는 느리지만 thread는 그렇지 않습니다.
  • fork는 메모리 공간을 공유하지 않습니다.
  • thread는 쓰레싱을 일으키지 않습니다.
  • thread는 DOS에서 작동합니다.
  • thread가 교착상태에 빠지면 전체 프로세스가 멈춥니다.
  • fork는 I/O가 완료되기를 기다리는 일시 중지를 이용할 수 있지만, thread는 그렇지 않습니다 (적어도 약간의 도움 없이는).

forkthread를 혼용해서는 안 됩니다.

Marshal은 어떻게 사용하나요?

Marshal은 객체를 파일이나 문자열에 저장하고 나중에 재구성하는 데 사용됩니다. 객체는 다음을 사용하여 저장할 수 있습니다.

Marshal.dump( obj [, io ] [, lev] )

io는 쓰기 가능한 IO 객체이고, lev는 객체가 역참조되어 저장되는 레벨을 지정합니다. lev 레벨의 역참조가 완료되고 객체 참조가 여전히 존재하는 경우 dump는 참조된 객체가 아닌 참조만 저장합니다. 이렇게 참조된 객체는 나중에 재구성할 수 없으므로 좋지 않습니다.

io가 생략되면 마샬링된 객체가 문자열로 반환됩니다.

다음을 사용하여 개체를 다시 로드할 수 있습니다.

obj = Marshal.load(io)
# 아니면
obj = Marshal.load(str)

여기서 io는 읽을 수 있는 IO 객체, str은 덤프된 문자열입니다.

trap은 어떻게 사용하나요?

trap은 코드 블록을 외부 이벤트(신호)와 연결합니다.

trap("PIPE") { raise "SIGPIPE" }