[루비 사용자 가이드] 기본적인 것들

루비/레일스 프로그래밍/루비 사용자 가이드 2009.02.06 10:47

여기서는 몇 가지 실제적인 내용을 다룹니다.

문(Statement) 구분자(delimiters)

몇몇 언어에서는 프로그램의 각 문장을 구분하기 위해 구두점(예:;)을 요구하곤 합니다. 루비는 그런 방식 대신 shcsh같은 셀이 사용하는 방식을 따릅니다. 한 줄에 여러 문장을 쓸 경우에는 세미콜론으로 구분을 해야 하지만, 줄이 바뀔 경우에는 줄바뀜(라인피드,linefeed)이 세미콜론 처럼 다뤄집니다. 만약 어떤 줄이 역슬래시(\)로 끝나면, 역슬래시 다음에 오는 줄바뀜은 무시됩니다. 이 기능을 사용해서 논리적으로는 한 줄인 프로그램을  여러 줄에 걸쳐서 짤 수 있습니다.

주석(Comments)

주석을 달아야 하는 이유가 무엇일까요? 잘 쓰여진 프로그램은 자기 자신을 잘 설명해주는 문서로써의 기능도 하는 경향이 있긴 합니다만(self-documenting), 여백에 힌트를 써 놓는것이 도움이 되곤 합니다. 또한, 다른 사람들이 여러분의 코드를 보고, 여러분과 동일하게 그 코드를 이해할 수 있다고 믿는 것은 잘못일 겁니다. 또, 실제적인 면에서는, 여러분 자신도 며칠 후에는 예전의 자신이 아니게 됩니다. 예전에 자기가 작성한 프로그램을 수정하거나 개선하려고 할 때, '내가 이걸 쓴건 맞는데, 도데체 뭔 뜻이지?'라고 말한 경험이 없는 사람은 별로 없을겁니다.

몇몇 경험많은 프로그래머는 코드와 모순되거나, 최신 사항을 반영하지 못하는 주석이 문제가 될 수 있다는 점을 지적하기도 하며, 그 지적은 확실히 맞는 말입니다. 분명 주석이 읽기 쉬운 코드를 대신할 수는 없습니다. 만약 여러분의 코드가 분명하지 않다면, 그 코드에 많은 버그가 있을 가능성도 높습니다. 루비를 배우는 동안에는 더 많은 주석을 달 필요가 있음을 발견할 지 모르겠습니다. 하지만, 자신의 생각을 단순하고 우아하고 읽기 쉬운 코드로 잘 표현하게 됨에 따라, 주석은 덜 필요하게 됩니다.

루비는 일반적인 스크립팅 언어처럼 파운드 기호(#)를 주석의 시작을 표시하기 위해 사용합니다. # 다음부터 줄의 끝까지 오는 모든 내용은 인터프리터가 무시합니다.

또한, 큰 주석 덩어리를 작성하는 것을 편하게 하기 위해 "=begin"로 시작하는 줄에서 시작해서 "=end"로 끝나는 줄까지의 모든 내용을 루비 인터프리터는 무시합니다.

#!/usr/bin/env ruby

=begin
**********************************************************************
  This is a comment block, something you write for the benefit of
  human readers (including yourself).  The interpreter ignores it.
  There is no need for a '#' at the start of every line.
**********************************************************************
=end

코드 조직하기

루비의 높은 동적 특성은 클래스, 모듈, 그리고 메소드는 각각을 정의하는 코드가 실행된 다음에야 존재할 수 있다는 것을 의미합니다. 만약 여러분이 더 정적인 언어에서 프로그램을 짜는 분이었다면, 이런 루비의 동적 특성에 놀랄 수도 있습니다.

# The below results in an "undefined method" error:

puts successor(3)

def successor(x)
  x + 1
end

비록 인터프리터가 스크립트 파일의 내용을 실행하기 전에 파일 전체의 문법을 체크하지만, def successor ... end 코드가 실제로 실행된 다음에야 successor 메소드가 생깁니다. 따라서, 스크립트를 나열하는 순서가 문제가 됩니다.

얼핏 생각해 보면, 이런 성격 때문에, 반드시 코드를 엄격하게 밑바닥에서부터 실행되도록 구성(즉, 다른 곳에서 필요한 정의를 먼저 실행되도록 구성)해야 할 것 같습니다. 하지만, 인터프리터가 메소드 정의를 처리할 때, 각각의 참조(변수,메소드,상수 등)에 대한 정의가 실제 메소드가 호출되는 시점 이전에만 된다는 것만 확실히 해 주면, 자유롭게 참조를 사용할 수 있습니다.(역주:아래를 보면 f_to_c가 정의되는 시점에서 scale이 보이지는 않지만, 실제 f_to_c가 호출될 때는 scale이 보인 다음입니다.)

# Conversion of fahrenheit to celsius, broken
# down into two steps.

def f_to_c(f)
  scale(f - 32.0)  # This is a forward reference, but it's okay.
end

def scale(x)
  x * 5.0 / 9.0
end

printf "%.1f is a comfortable temperature.\n", f_to_c(72.3)

이런 방식이 Perl이나 Java보다는 불편해 보이지만, 실제로는 C언어를 프로토타입(prototype) 없이 사용하는 경우보다 더 제약이 적은 상황입니다(C언어에서 프로토타입을 사용하지 않는 경우에는, 모든 참조에 대해 참조 관계를 명확히 해서, 정의가 참조 이전에 오게 작성해야 합니다). 탑레벨 코드를 소스 파일의 맨 나중에 넣는 것은 항상 잘 동작합니다. 프로그램이 원하는데로 동작하도록 하는 가장 현명하고 쉬운 방법은 main 함수를 파일의 맨 앞에서 정의하고, 파일의 맨 마지막에 그 함수를 호출하는 것입니다.

#!/usr/bin/env ruby

def main
  # Express the top level logic here...
end

# ... put support code here, organized as you see fit ...

main # ... and start execution here.

또한, 루비는 복잡한 프로그램을 읽기 쉽고 재사용하기 쉬우며 논리적으로 연관성이 있는 덩어리로 나눠 사용할 수 있도록 돕는 도구를 제공합니다. 우리는 모듈 억세스를 위한 include를 이미 살펴보았습니다. 여러분은 또한 loadrequire가 유용하다는 것을 알게 될 겁니다. load는 마치 파일의 내용을 복사해서 넣은 것처럼 동작합니다(C의 #include 전처리 명령과 유사합니다). require는 조금 더 복잡해서, 코드가 최대 한번, 필요할 경우에만 읽히도록 제한 합니다.

이제 끝입니다...

이 가이드는 여러분이 루비로 프로그램을 작성하는데 필요한 최소한입니다. 더 깊은 의문이 떠오를 때면 사용자 커뮤니티나 온라인 리소스, 출판된 문서에서 정보를 얻으실 수 있습니다.

행운을 빕니다. 재미있게 코딩하세요~~

신고
Trackback 0 : Comment 1

티스토리 툴바