본문 바로가기

Private/SW Programming

[2] 루비 프로그램의 구조와 실행

어휘 구조


 루비 인터프리터는 루비 프로그램을 토큰의 나열로 인식합니다. 다시 토큰은 주석, 리터럴, 기호들, 식별자, 키워드로 나누어 지고요.

 이러한 토큰을 나누는 기준은 공백이 되는데요. 이러한 부분은 각 언어가 미묘하게 다른 부분이라 반드시 이해하고 가는 편이 혼란이 없을것 같네요.

 

주석

  일반적인 주석은 #으로 시작해서 그줄 끝까지 입니다.

예를들면 아래와 같죠.

#이글은 주석

x = "#this is a string" #부터 주석

y = \#this is a regular expression\ #부터 주석

 

내장 문서

 내장문서라는 형식의 주석이 있습니다.

 아래 처럼 =begin 으로 시작하는 줄부터  =end 로 끝나는 줄까지 입니다.

=begin 여기부터가 주석이구요.

여기도 주석입니다.

=end 여기도 주석이에요

 

 

문서용 주석

 루비 프로그램은 메서드나 클래스, 모듈의 정의 앞에 특정 형식의 주석을 추가해서 API 문서를 포함할수 있습니다.

 Javadoc 과 같은 기능인데요. rdoc 도구를 이용해서 주석을 추출하고 ri 도구를 이용해서 읽어냅니다.

 

  보통은 앞서 설명한 방식으로 구현하는데요.

 문서용 주석은 문서화 하고 싶은 모듈이나 클래스 앞에 위치해야 합니다.

 각 줄 첫글자가 #인 복수행의 주석의 형식이거나 아니면 내장문서 주석을 이용하여 "=begin rdoc"형식으로 시작해도 됩니다.

 

리터럴

 리터럴은 간단히 상수라고 생각하시면 됩니다. 코드에 직접 사용하게 되는 것들입니다. 숫자, 문자열, 정규식 표현이 있구요. 단일 토큰이 아닌 리터럴도 있습니다.

간단한 것들만 예를 들면 아래와 같죠.

1 # 정수 리터럴

1.0 # 부동 소수점 리터럴

'1' # 문자열 리터럴

"1" # 문자열 리터럴

/1/ # 정규식 리터럴

 

기호

 루비에서 기호는 +,-,*,|| 같은 연산자와 리터럴 구분을 위해 사용되는 ?.! 등과 같은 기호 문자등이 있습니다.

 

식별자

 루비의 식별자는 단순히 이름을 의미하는데요. 식별자는 영자, 숫자, 언더스코어(_)로 이루어질수 있는데요. 다른 많은 언어들과 마찬가지로 숫자는 맨앞에 올수 없죠.

 클래스와 모듈은 첫글자가 대문자로 시작해야 한다고 합니다.

(특이한 것은 첫글자가 대문자 A-Z로 시작하는 식별자는 상수를 나타내기도 합니다. 이 값을 바꾸려고 하면 에러는 아닌데 인터프리터가 경고를 하게 됩니다.)

i

x2

old_value

_internal # _로 시작하는 식별자

PI # 상수

 

 

대소문자, 유니코드 문자 식별자

 루비는 대소문자를 구별합니다. 또한 ASCII 외외의 인코딩을 사용해서 루비 프로그램을 작성할수도 있습니다.예를들면 한자도 가능하구요.

 다만 ASCII이외의 문자를 쓰려면 파일 앞부분에 특별한 주석을 추가하여 인터프리터에게 알려주어야 합니다.

 

식별자 속 기호

 식별자에 앞이나 뒤에 기호를 사용하면 특별한 의미와 기능이 부여됩니다.

$ 전역 변수는 선두에 $를 붙여 표시합니다. 펄에서 넘어온 문법으로 보입니다.

@ 앞에 @를 붙이면 인스턴스 변수를 의미합니다. @@를 붙이는 것은 클래스 변수에서 사용되구요

? true/false를 돌려주는 메서드 이름 뒤에는 ?를 붙입니다. 관습입니다.

! 이 메서드를 사용할때는 주의하라는 의미로 사용되는데요. 객체를 내부에서 바꿀수도 있다는 의미입니다.

= 메서드 뒤에 =를 붙일수도 있습니다. 이 메서드는 등호 없이 메서드 이름을 넣는 것만으로도 실행시킬수 있습니다.

 

$file              # 전역변수

@data           # 인스턴스 변수

@@counter    # 클래스 변수

empty?          # true/false 돌려주는 메서드

sort!              # 함수 주의

timeout=         # 등호 없이도 사용가능한..

 

키워드

 키워드는 특별한 의미로 다루는 문구들입니다. 

__LINE__ __ENCODING__ __FILE__ BEGIN END alias and begin break

case class def defined? do else elsif end ensure false for if

in module next nil not or redo rescue retry return self super

then true undef unless until when while yield

 

이중에서도 아래에 있는 키워드는 위치에 따라 좀더 특벼한 의미를 부여받기도 합니다.

=begin     =end     __END__

보통은 다른 언어에서는 이런 키워드들을 다른 용도로 사용이 불가합니다만...

Ruby에서는 접두어(@,@@,$등)를 사용하면 인스턴스나 클래스등으로 사용이 가능한다고 합니다. 하지만 코드를 읽기 어렵게 하는 그런 짓은 안하는게 좋겠죠?

 

공백 문자

 각 언어마다 공백 문자를 처리하는 방식이 좀 다릅니다.  저 같은 경우에는 C,C++에 익숙해서 다른 언어 공백에 대한 처리가 어렵더라구요.

 Ruby에서는 공백, 탭, 줄바꿈 자체는 토큰을 구별하기 위한 용도로 사용이 됩니다만 모든 공백 문자가 무시되는 것은 아닙니다. 일부는 필수적으로 필요하기도 하구요. 일부는 금지가 되기도 합니다. 이런 부분이 어려운 부분인데요.

 그래서 공백에 따라서 다른 프로그램이 되기도 하구요.

 

문장 끝을 나타내는 줄바꿈

 루비에서의 문장 끝을 표현하는 방법은 여러가지가 있습니다. 때론 모호하게 보이는 부분이라서 이부분에서 혼란을 느낄수도 있을것 같구요.

 먼저 Java, C, C++ 같은 언어에서 사용하는 세미콜론(;)으로 문장이 끝남을 알려줄수 있는데요. 이 방법은 여러문장을 나열할때 사용한다고 합니다.

 보통은 그냥 줄바꿈으로 문장의 끝을 표현하구요.

 하지만 여기 함정이 있습니다. 단순히 줄 바꿈한다고 해서 문장이 끝났다고 인식하지 않는 경우가 있거든요.

 문장이 완벽하지 않다고 Interpreter가 판단하거나  특정 기호 뒤에 줄바꿈이 오면 문장이 아직 안끝났다고 판단하여 다음 줄도 합쳐서 문장으로 인식합니다.

 그 기호로는 컴마(,), 마침표(.), 역슬래쉬(/)가 있습니다. 

# 첫줄은 불완전한 식으로 다음줄까지 하나의 문장으로 인식한다.

sum = math +    

english 

 

# 첫줄에 역슬래쉬(\)가 있으므로 다음 줄도 하나의 문장으로 인식

var sum = math + history \      

+ english

 

# 첫줄까지 문장은 완벽하므로 하나의 문장으로 인식

var sum = math + history   

  + english

 

Ruby 1.9 에서는 체인형식의 함수 호출을 지원하기 위해 아래와 같은 경우도 하나의 문장으로 인식한다고 합니다.

textbooks = Array.new

.push("math")

.push("cat")

 

공백과 메서드 호출

 메서드 호출은 괄호가 있어야 합니다만 일정 조건을 만족한다면 생략이 가능합니다.

 좋아보지만 때에 따라서는 엄청난 혼란을 야기합니다. 저는 이런게 싫어요..ㅜㅜ

function(3+2)+1

function (3+2)+1

 위 구문은 함수 이름 뒤에 공백 문자 하나를 제외하면 똑같습니다. 하지만 그 결과는 다르죠. 왜 일까요?

 function(3+2)+1은 f 함수에 5라는 값이 넘어가고 그 결과 값에 +1 하게 됩니다.

 하지만 function (3+2)+1 의 경우는 괄호가 생략되었다고 판단하여 (3+2)+1 모두를 인수로 판단합니다.

 이런 실수를 피하는 방법은 경고 모드( -w)를 지정하면 되는데요. 인터프리터가 가동시 애매한 경우에 경고를 주게 됩니다.

 만약 아래와 같은 코드를 실행했다면...

3.downto (1) do |x|
print x
end

 3.downto (1) 사이에 애매한 공백이 있습니다. 이 문장은 괜찮지만 앞예제와 같다면 문제가 생길수도 있겠죠..

 어쨋든 실행을 해보면... 아래와 같이 경고를 출력하는 군요..

C:/Users/jonghyun.yoo/My Documents/Aptana Studio 3 Workspace/testCode1/firstFile.rb:3: warning: don't put space before argument parentheses
321

 

 

구문 구조


블록 구조

대부분의 언어처럼 루비도 모듈/클래스/메서드/루비 문장은 대부분 코드 블록으로 이루어져 있습니다.

블록은 중괄호나 do end로 둘러싸인 것을 말합니다.

2.times { print"Ruby!!!" }

2.times do
  print"Ruby!!"
end 

본체라고 부르는 것도 있습니다. 클래스, 메서드 정의 같이 중괄호나 do,end를 사용하지 않는 코드 묶음이라고 할까요.

module Func
  class Class1
    def init(filename)
       if line[0,1] == "#"
         next
     end            # 메서드 본체 끝
   end              # 클래스 본체 끝
end                 # 모듈 본체 끝

이렇게 본체(body), 블록(Block)을 구분하기도 하는데, 큰 의미는 없을것 같네요.

 

파일 구조

 루비 파일은 몇가지 규칙을 갖고 있는데요.

 유닉스 계열 시스템에서 루비 프로그램을 돌리기 위해서는 첫줄에 'shebang' 이라는 코드가 있어야 하구요.

 (Shebang 는 샤방이라고 읽습니다. 유닉스에서의 Script를 위해서 기존에 사용하던 용어입니다)

 'coding' 이라는 주석은 파일의 첫줄에 있어야 합니다. 그자리에 shebang가 있다면 두째줄에 있어야 하구요

 __END__ 토큰이 있다면 코드는 그부분에서 중단됩니다. 앞뒤 공백이 없어야 합니다.

 여러 루비 파일들을 참조해서 사용해야 한다면 require 키워드를 사용해서 코드 모듈을 찾아 사용할수 있습니다.

 이 규칙을 한번에 표현하면 아래와 같겠네요

#!/usr/bin/ruby -w

# -*- coding : utf-8 -*-

require 'socket'

# 코드가 있는 자리겠죠?

__END__

여기는 데이터가 있어도 상관 없어요..코드는 __END__에서 중단되거든요.

 

프로그램 인코딩


 

 루비는 기본적으로 ASCII로 인코딩되었다고 가정합니다만, 스스로 인코딩을 지정하거나 인터프리터 기동시 파일인코딩 전달하면 다른 방식의 인코딩도 가능합니다.

 다시 말하면 주석/문자열/정규식에 유니코드 문자나 한자들도 인코딩 설정에 따라 사용할수 있는 거죠.

 

프로그램 인코딩 지정

루비 1.8 , 루비 1.9 모두 -K 옵션을 사용해서 인코딩을 지정할수 있습니다. 예를 들어 UTF-8은 -Ku, EUC-JP는 -Ke, SJIS는 -Ks 같은 방식입니다.

루비 1.9에서는 이 방법외에 파일 앞에 CODING 키워드를 사용하여 인코딩 방식을 지정합니다. 이 방법이 더 많이 사용된다고 합니다.

# coding:utf-8

# -*- coding: utf-8 -*-    <== Emacs 사용자의 경우

# vi: set fileencoding=utf-8:   <== vi 사용자의 경우

 

소스 인코딩과 기본 외부 인코딩

기본 외부 인코딩이라는 부분이 있습니다. 파일과 스트림을 읽을때 기본으로 사용하는 인코딩을 의미합니다.

프로그램 인코딩과 마찬가지로 -K 옵션으로 동시 설정이 가능합니다만 Ruby 1.9부터 -E 옵션으로 설정도 가능합니다.

아래는 -E 옵션으로 사용하는 예입니다.

ruby -Eutf-8 

ruby -E utf-8

ruby --encoding utf-8

ruby --encoding=utf-8

 

 

 

프로그램 실행


루비는 C/C++와 java같은 언어와는 다르게 main이 없습니다.

인터프리터가 있는 스크립트 언어 답게 맨 위에 있는 줄부터 순차적으로 실행합니다. 그리고 파일 끝까지 읽거나 종료문장을 실행하거나 __END__ 코큰을 만나면 종료합니다.