Reading and ‘Riting

Ruby는 다영한 I/O 라이브러리를 제공합니다. 하지만 이 책에서는 간단한 메소드 몇개 만을 사용합니다. 그 중에 두 개를 이미 보셨을 것입니다. puts와 print입니다. puts는 puts 뒤에 오는 아규먼트들을 각 각 newline(자바에서는 \n)을 추가하여 화면에 출력하며, print는 newline 문자 없이 아규먼트들을 출력해 줍니다. 또하나 자주 사용되는 것은 printf입니다. 이것은 형식 문자열로 아규먼트를 제어하는 형식입니다.(C나 Perl에 처럼)

printf “Number: %5.2f, String: %s”, 1.23, “hello”

이렇게 입력을 하면

Number:  1.23, String: hello=> nil

이렇게 출력됩니다. %f는 실수를 출력할 것이고 %s는 문자열을 출력할 것이라는 것입니다. %와 f사이의 숫자는 (allowing five characters in total, with two after the decimal point) 이렇습니다. 즉 앞에 . 앞에 있는 숫자는 총 숫자를 말하고 . 뒤에 있는 숫자는 소숫점을 말한다고 합니다. 그래서 출력 실험을 해봤습니다.

irb(main):017:0> printf “%6.3f, %s”, 123456789.1234567, “test”
123456789.123, test=> nil
irb(main):018:0> printf “%6.4f, %s”, 123456789.1234567, “test”
123456789.1235, test=> nil
irb(main):019:0> printf “%1.4f, %s”, 123456789.1234567, “test”
123456789.1235, test=> nil

. 뒤에 있는 숫자를 변경 해보니 결과물의 소숫점의 자릿수가 바뀌는 것을 확인 할 수 있습니다. 하지만 . 앞의 숫자에 어떤 영향을 받고 있는 것인지는 확인 할 수 없었습니다.

프로그램에 값을 입력시키는 방법도 여러가지가 있습니다. 그 중에 가장 전통적인 방법으로 gets를 사용합니다.

irb(main):022:0> line = gets
hi
=> “hi\n”
irb(main):023:0> print line
hi
=> nil
irb(main):024:0>

gets는 방금 읽어들인 문장을 리턴하는데 그 때 리턴되는 것을 전역 변수인 $_ 안에 저장합니다. 이 변수는 많은 경우에 기본으로 사용되는 특별한 변수 입니다. print를 아규먼트 없이 호출하면 &_ 안에 있는 것을 호출하게 됩니다. if 나 while문을 정규 표현식과 사용한다면 그 표현식은 $_ 변수에 대응하여 작동합니다. 예를 들어 다음 프로그램은 “Ruby”라는 단어간 들어간 모든 줄을 출력합니다.

while gets           # assigns line to $_
 if /Ruby/          # matches against $_
   print            # prints $_
 end

이 것을 저번 글에서 배웠던 이터레이터를 사용하여 다음과 같이 나타낼 수도 있습니다.

ARGF.each { |line|  print line  if line =~ /Ruby/ }

Blocks and Iterators

이번 세션에서는 간단하게 Ruby의 장점중에 하나를 설명하겠습니다. 코드 블럭을 살펴보려고 합니다. 코드 블럭은 callback을 구현하거나(Java의 anonymous inner class보다 간단하게), 코드 덩어리(C의 funtion pointer보다 더 유연한)를 넘겨주거나, 이터레이터를 구현할 때 사용할 수 있습니다.

코드 블럭은 ( )사이 또는 do 와 end 사이의 코드 덩어리 입니다.

{ puts "Hello" }       # this is a block

do                     #
 club.enroll(person)  # and so is this
 person.socialize     #
end                    #

코드 블럭을 만들어 두고 yield 를 사용하여 여러번 호출 할 수 있습니다.

def callBlock
 yield
 yield
end

callBlock { puts “In the block” }

callBlock 이라는 메소드 안에는 yield 를 두 번 사용했습니다. 그리고 오른쪽에 코드 블럭이 있군요. 그럼 이 코드 블럭을 두 번 호출 하게 될 테니 화면에 in the block 가 두번 찍힐 것입니다.

In the block
In the block


You can provide parameters to the call to
yield: these will be passed to the block. Within the block, you
list the names of the arguments to receive these parameters between
vertical bars (``|'').

def callBlock yield , end callBlock { |, | … }

코드 블럭은 Ruby에서 이터레이터를 구현할 때 사용됐습니다.

a = %w( ant bee cat dog elk )    # create an array
a.each { |animal| puts animal }  # iterate over the contents

이 것의 결과는 다음과 같습니다.

ant
bee
cat
dog
elk

each라는 메소드가 어떻게 구현되어 있는지 보겠습니다.

# within class Array...
def each
 for each element
   yield(element)
 end
end

You could then iterate over an array’s elements by calling itseach method and supplying a block. This block would be called foreach element in turn.

[ 'cat', 'dog', 'horse' ].each do |animal|
 print animal, " -- "
end

produces:

cat -- dog -- horse --

Java와 C에서 사용하는 여러 loof를 Ruby에서는 단순한 메소드 호출을 사용하여 할 수 있습니다.

5.times {  print "*" }
3.upto(6) {|i|  print i }
('a'..'e').each {|char| print char }

produces:

*****3456abcde

*을 출력하는 코드 블럭을 다섯번 호출하고, 3~6까지 출력하고, a~e까지 출력했습니다.


Regular Expressions

Regular Expressions

모든 프로그래머들은 Ruby에 이미 만들어져 있는 문자열, 정수, 실수, 배열 등과 같은 것에 익숙할 것입니다. 하지만 Ruby가 가지고 있는 regular expression은 스크립트 언어라고 불리는 것에만 있습니다. 말하기 부끄럽지만 text를 다루는데는 regular expression이 매우 유용합니다.

여기서는 그 전부에 대해 다루지는 않고 regular expression을 사용하는 몇가지 예만 살펴 보겠습니다. 56페이지 부터 시작하는 부분에서 이것에 대한 모든 것을 볼 수 있을 것입니다.

regular expression은 문자열에서 특정 패턴을 구분하는 간단한 방법입니다. Ruby에서는 / / 슬러쉬 사이에 패턴을 적어 넣음으로써 regular expression을 작성할 수 있습니다(/패턴/). 그리고 Ruby에서 이것은 당연히 객체이고 객체처럼 다뤄 집니다.

예를 들어 문자열에 Perl또는 Python을 포함하는 문자열에 매치하는 패턴을 작성하고 싶다면 다음과 같은 regular expression을 사용할 수 있습니다.

/Perl|Python/

“|” 파이프 문자를 이용하여 여러개의 문자열을 구분 할 수 있습니다. 그리고 괄호도 사용할 수 있지요. 따라서 위의 표현을 다음괕이 적을 수도 있습니다.

/P(erl|ython)/

그리고 반복되는 패턴을 기술 할 수도 있습니다. /ab+c/는 문자열이 a를 가지고 있고 a뒤에 하나 또는 그 이상의 b가 있고 그 뒤에 c가 있는 문자열에 매칭됩니다. +대신에 *를 써서 /ab+c/라고 표현하면 a뒤에 b가 없거나 하나 이상일 수 있고 그 뒤에 c가 있는 문자열에 매칭됩니다.

여러 문자 그룹중 하나를 매칭 시킬 수도 있습니다. \s 는 공백 문자(스페이스, 탭, 새줄 등등)와 매칭 됩니다. \d는 모든 정수를 매칭 됩니다. and “\w”, which matchesany character that may appear in a typical word. The single character“.” (a period) matches any character.

이것들을 사용하여 몇가지 유용한 regular expression을 만들 수 있습니다.

/\d\d:\d\d:\d\d/     # a time such as 12:34:56
/Perl.*Python/       # Perl, zero or more other chars, then Python
/Perl\s+Python/      # Perl, one or more spaces, then Python
/Ruby (Perl|Python)/ # Ruby, a space, and either Perl or Python

“=~” 이 오퍼레이션은 문자열에 regular expression을 매칭 하는데 사용할 수 있습니다. 만약에 문자열에서 해당하는 패턴이 발견되면 =~ 는 그 패턴이 시작하는 위치를 리턴하고 없다면 nil을 리턴합니다. 이 말은 if문이나 while문의 조건식에 사용할 수 있다는 것입니다. 다음의 예는 문자열에 ‘Perl’ 또는 ‘Python’이 있는지 확인합니다.

if line =~ /Perl|Python/
 puts "Scripting language mentioned: #{line}"
end

Ruby의 메소드를 사용하여 패턴에 매칭되는 문자열을 다른 문자열로 교체 할 수 있습니다.

line.sub(/Perl/, 'Ruby')    # replace first 'Perl' with 'Ruby'
line.gsub(/Python/, 'Ruby') # replace every 'Python' with 'Ruby'

이 책 전반에 걸쳐 regular expression을 살펴 볼 것입니다.

Control Structures

Control Structures

Ruby는 if나 while 같은 유용한 제어문을 가지고 있습니다. Java, c, Perl 프로그래머들은 이 제어문 바디에 괄호를 뺸 것을 눈치 챗을 것입니다. 대신에 자바는 end라는 키워드로 바디를 구분합니다.

if count > 10
 puts "Try again"
elsif tries == 3
 puts "You lose"
else
 puts "Enter a number"
end

while문도 비슷하게 end를 사용합니다.

while weight < 100 and numPallets <= 30
 pallet = nextPallet()
 weight += pallet.weight
 numPallets += 1
end

Ruby의  statement modifier라는 것을 사용하여 while이나 if문을 줄여 쓸 수가 있습니다. 사용 법은 먼저 딱 한 문장 만 기술을 하고 그 뒤 if나 while 키워드를 사용하고 조건을 명시하면 됩니다.

예를 들어 아래에 한 문장의 간단한 if문이 있습니다.

if radiation > 3000
 puts "Danger, Will Robinson"
end

이것을 아래와 같이 간단히 줄일 수 있습니다.

puts "Danger, Will Robinson" if radiation > 3000

한 문장의 while문이 아래에 있습니다.

while square < 1000
  square = square*square
end

이것도 아래 처럼 줄일 수 있습니다.

square = square*square  while square < 1000

Arrays and Hashes

Arrays and Hashes

Ruby의 array와 hash는 인덱스가 있는 collection입니다. 둘 다 객체를 담아 두고 key를 사용하여 접근하는 콜렉션입니다. array에서 key는 정수이지만 hash는 어떤 객체도 key가 될 수 있습니다. 둘 모두 새로운 요소를 추가할 때 커기제 됩니다. array에 접근을 하는게 보다 효율 적이지만 hash는 보다 유연함을 제공합니다. 어떤 array이나 hash들도 여러 타입의 객체를 담아 둘 수 있습니다. 이 말은 하나의 array에 정수, 문자열, 실수를 담을 수 있다는 것입니다.

[ ] 이 괄호 사이에 요소들을 나열 하는 array literal을 사용하여 새로운 배열을 생성하고 초기화 할 수 있습니다. array 객체를 가지고 객체에 있는 각각의 요소들에 [] 안에 index를 사용하여 접근할 수 있습니다. 다음의 예에서 봅시다.

a = [ 1, 'cat', 3.14 ]   # array with three elements
# access the first element
a[0] » 1
# set the third element
a[2] = nil
# dump out the array
a » [1, "cat", nil]

array 객체의 생성자를 사용하여 생성하거나 요소들이 없는 비어있는 괄호 [] 를 사용하여 배열을 생성할 수도 있습니다. Array.new .

empty1 = []
empty2 = Array.new

단어들의 배열을 생성할 때 “” 와 , 를 사용하기가 매우 번거로울 수 있는데 이 때 사용하기 편한 것이 있습니다. 바로 %w 입니다. 다음과 같이 사용할 수 있습니다.

a = %w{ ant bee cat dog elk }
a[0] » "ant"
a[3] » "dog"

Ruby의 hash는 배열과 비슷합니다. hash는 [] 말고 {} 이 괄호를 사용합니다. 반드시 하나의 요소에는 두 개의 객체가 제공되어야 합니다. 하나는 key 하나는 value입니다.

예를들어, 악기들을 오케스크라 위치에 따라 매핑하고 싶다면 다음과 같이 할 수 있습니다.

instSection = {  'cello'     => 'string',  
'clarinet'  => 'woodwind',  
'drum'      => 'percussion',  
'oboe'      => 'woodwind',  
'trumpet'   => 'brass',  
'violin'    => 'string'}

Hash는 array와 같이 [] 괄호를 사용하여 index화 됩니다.

instSection['oboe'] » "woodwind"
instSection['cello'] » "string"
instSection['bassoon'] » nil

마지막 예가 보여주듯이 hash에 해당하는 key가 없는 경우에 기본적으로 nil을 반환합니다. 하지만 가끔은 여러분이 원하는 기본값을 반환하도록 하고 싶을 것입니다. 예를 들어 해당하는 key가 몇 번 출현하는지 카운팅하는 hash의 경우 기본값을 0으로 하고 싶을 것입니다. 이것은 hash를 생성할 때 생성자에 기본값을 인자로 넘겨 주는 방식으로 할 수 있습니다.

histogram = Hash.new(0)
histogram['key1'] » 0
histogram['key1'] = histogram['key1'] + 1
histogram['key1'] » 1

배열과 해쉬 객체는 매우 유용한 메소드들을 많이 가지고 있습니다. 33page와 278page~317page에 걸쳐 이 메소드들에 대해 자세하게 나와있습니다.