ruby language 입문 및 소개

90
Ruby Language 입입 입 입입 2006. 9. 입 입 입

Upload: yanka

Post on 27-Jan-2016

167 views

Category:

Documents


7 download

DESCRIPTION

Ruby Language 입문 및 소개. 2006. 9. 이 지 행. Ruby. 1990 년대 일본인 Yukihiro Matsumoto (a.k.a matz) 에 의해 만들어짐 . 최근 몇 년 사이 미국에서도 엄청나게 주목을 받고 있음 특징 Interpreted scripting language for quick and easy objected-oriented language Perl 과 같은 편리성과 생산성 Smalltalk 와 같은 여러 OOP 언어에서 영향을 받은 pure OOP - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Ruby Language  입문 및 소개

Ruby Language 입문 및 소개

2006. 9.

이 지 행

Page 2: Ruby Language  입문 및 소개

Ruby

• 1990 년대 일본인 Yukihiro Matsumoto (a.k.a matz) 에 의해 만들어짐 .– 최근 몇 년 사이 미국에서도 엄청나게 주목을 받고 있음

• 특징– Interpreted scripting language for quick and easy objected-orie

nted language– Perl 과 같은 편리성과 생산성– Smalltalk 와 같은 여러 OOP 언어에서 영향을 받은 pure OOP– 배우기 쉽고 , 읽기 쉬운 스타일– Open Source. 어느 OS 에서나 , 자유롭게 이용할 수 있음– 프로그래밍 자체가 매우 재미있음 (fun)– 전체적으로 잘 균형잡힌 이상적인 언어 : elegant, fun and pragma

tic

• Ruby is a pure object-oriented programming language with a super clean syntax that makes programming elegant and fun. Ruby successfully combines Smalltalk's conceptual elegance, Python's ease of use and learning, and Perl's pragmatism. Ruby originated in Japan in the early 1990s, and has started to become popular worldwide in the past few years as more English language books and documentation have become available.

Page 3: Ruby Language  입문 및 소개

참고도서

• Programming Ruby – The Pragmatic Programmers’ Guide, 2nd– Dave Thomas, et.al..– Ruby Community 에서 유명함 : PickAxe– 1 판은 인터넷에서 무료로 볼 수 있음

• 기타 참고자료– 루비 공식 사이트 : http://www.ruby-lang.org– Ruby on Rails : http://www.rubyonrails.org/– Ruby Cookbook– Agile Web Development with Rails: A Pragmatic Guide– 번역서 아직 하나도 없음

Page 4: Ruby Language  입문 및 소개

목 차

• Ruby.new

• Ruby.each– Class, Object and Variable, Container, Block and Iterator– Standard Type, Method, Expression, Exception, Module

s, I/O

• Ruby.inspect– Threads, Tool, Ruby and Web– Duck Typing– Classes and Objects in Ruby– Etc…

Page 5: Ruby Language  입문 및 소개

Ruby.new

Page 6: Ruby Language  입문 및 소개

Ruby : 순수 객체지향 언어

• 거의 모든것이 Object. 결과물도 Object.

• 심지어 현재 Context 도 Object, 클래스도 Class 라는 클래스의 Object

• Method 호출 보다는 Message 를 Object 에 전달한다는 개념이 더 강함

– 함수 호출시 괄호 없어도 됨– 숫자나 문자열도 Integer, String 의 Object– 세미콜론 없어도 됨 . Ruby 는 Line 단위 파싱이 기본임

song1 = Song.new("Ruby Tuesday") "gin joint".length "Rick".index("c") -1942.abs sam.play(song)

number = Math.abs(number) // Java code

Page 7: Ruby Language  입문 및 소개

기본 적인 사항들

• 함수 선언 및 사용– def ~ end

– 변수 interpolation : #{ expression }

– 함수내에 return 이 없으면 맨 마지막 expression 을 리턴– 주의 : 함수 선언에 입력 , 출력 변수에 대한 Type 설정 이 없음

def say_goodnight(name)

result = "Good night, #{name}“

return result

end

puts say_goodnight('Pa')

def say_goodnight(name) "Good night, #{name}" end puts say_goodnight('Ma')

Page 8: Ruby Language  입문 및 소개

• Array– 하나의 Array 에 여러 Type

의 데이터가 들어갈 수 있음– 재미있는 Operator 들 많이

있음

• Hash– Index 대신 key 값이

들어가면 됨

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 ]

a = [ 'ant', 'bee', 'cat', 'dog', 'elk' ] a[0] “ant” a[3] -> “dog” # this is the same: a = %w{ ant bee cat dog elk } a[0] “ant” a[3] -> “dog”

inst_section = { 'cello' => 'string', 'clarinet' => 'woodwind', 'drum' => 'percussion', 'oboe' => 'woodwind', 'trumpet' => 'brass', 'violin' => 'string' } inst_section['oboe'] inst_section['cello'] inst_section['bassoon']

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

Page 9: Ruby Language  입문 및 소개

• 변수명– Convention( 관습 ) 이 아니라 interpreter 가 변수명을 보고

다르게 처리하는 규칙이다 .– 대소문자 , @ 를 정확히 사용해야 함

• nil – C 나 Java 의 Null Pointer 와는 다름 : nil 도 하나의 객체임– C 나 perl 의 0 과도 다름 : 0 이 아니라 nil 이라는 객체임

Variables Constants and Class Names Local Global Instance Class

name $debug @name @@total PI

fishAndChips $CUSTOMER

@point_1 @@symtab FeetPerMile

x_axis $_ @X @@N String

thx1138 $plan9 @_ @@x_pos MyClass

_26 $Global @plan9 @@SINGLE Jazz_Song

Page 10: Ruby Language  입문 및 소개

• Control Structure– if elsif else end– Perl 스타일의 modifier 지원

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

puts "Danger, Will Robinson" if radiation > 3000

– while end» 괄호 없어도 됨

while weight < 100 and num_pallets <= 30 pallet = next_pallet() weight += pallet.weight num_pallets += 1 end

square = 2 square = square*square while square < 1000

• Regular Expression– Built-in type : 라이브러리가 아님 (Perl 과같이 강력함 )– 대부분의 Operation 지원

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

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

Page 11: Ruby Language  입문 및 소개

• Blocks and Interators– Block 선언

– Block 을 method 와 연결시키기» Function pointer 와는 비슷하지만 많이 다르다 .» Method 와 해당 Block 이 연결되며 , method 에 함수 뿐

아니라 , Context 가 함께 전달된다 . (Closure)» Method 내의 yield 함수에 의해 연결된 Block 이

실행된다

{ puts "Hello" } # this is a block

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

def call_block puts "Start of method" yield yield puts "End of method" end

call_block { puts "In the block" }

Start of methodIn the blockIn the blockEnd of method

Page 12: Ruby Language  입문 및 소개

– Block 과 변수 주고받기» Method 에서 꺼꾸로 Block 에게 | var1 , val2, … |

형태로 변수를 전달할 수 있음» Method 내에서 여러 차례 Block 을 호출 Interator

– Iterator 예

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

# within class Array... def each for each element # <-- not valid Ruby yield(element) end end

[ 'cat', 'dog', 'horse' ].each {|name| print name, " " } 5.times { print "*" } 3.upto(6) {|i| print i } ('a'..'e').each {|char| print char }

cat dog horse *****3456abcde

Page 13: Ruby Language  입문 및 소개

Ruby.each

Page 14: Ruby Language  입문 및 소개

• Class 선언 및 상속

– initialize : 생성자에 해당됨 . 밖에서는 new 를 이용하여 호출

– 이미 정의되어 있는 Class 에 동적으로 method 를 붙이거나 변경시킬 수 있음

Classes, Objects and Variables

class Song def initialize(name, artist, duration) @name = name @artist = artist @duration = duration endend

song = Song.new("Bicylops", "Fleck", 260) song.to_s “#<song:0x1c7ec4>”

class Song def to_s "Song: #@name--#@artist (#@duration)" endendsong = Song.new("Bicylops", "Fleck", 260)song.to_s “Song: Bicylops—Fleck (260)”

Page 15: Ruby Language  입문 및 소개

• 상속– 다중상속 허용안함– Super 함수로 부모의 생성자 호출– 참고 : 모든 클래스는 Object 라는 부모클래스로부터 상속됨

– 참고 : @lyrics 는 그 자체로 변수명이며 , instance variable 을 나타냄 .

따로 선언할 필요는 없다

• Attribute– Object 는 내부 State(instance variable) 을 가지고 있는데 , Ruby

에서는 기본적으로 이것을 접근할 수 ( 볼 수도 , 쓸 수도 ) 없다 . – 하지만 , 외부에서 Object 의 어떤 값이나 상태를 요청할 경우 밖에서 볼 수 있도록 Class 가 제공하는데 , 이를 Attribute 라고 한다 .

– Attribute 는 밖에서 볼때는 Variable 처럼 보이지만 내부적으로는 method 로 구현된다

class KaraokeSong < Song def initialize(name, artist, duration, lyrics) super(name, artist, duration) @lyrics = lyrics endend

Page 16: Ruby Language  입문 및 소개

• Readable attribute– 일종의 getter 함수– 밖에서 볼때는 변수를 조회하는

것 같음

– 하지만 이것은 아래와 같이 간단하게 표현할 수 있다 .

class Song def name @name end def artist @artist end def duration @duration endendsong = Song.new("Bicylops", "Fleck", 260)song.artist “Fleck”song.name “Bicylops”song.duration 260

class Song attr_reader :name, :artist, :durationend

• Readable attribute– 일종의 setter 함수– 밖에서 볼때는 변수에 대입하는

것 같음

– 하지만 이것은 아래와 같이 간단하게 표현할 수 있다 .

class Song def duration=(new_duration) @duration = new_duration endendsong = Song.new("Bicylops", "Fleck", 260)song.duration 260song.duration = 257 # updatesong.duration 257

class Song attr_writer :durationendsong = Song.new("Bicylops", "Fleck", 260)song.duration = 257

Page 17: Ruby Language  입문 및 소개

• Virtual attribute– 내부 instance variable 을 변환시켜 외부에 보여줄 수 있다 .– Method 이지만 밖에서 볼때는 하나의 변수처럼 보인다 .

• Class Variable ( @@ 변수명 )– Class 에 속하는 object 들이 공유하는 변수– 하나의 Class 에 유일하게 존재함

• Class Method– 특정한 Object 와 관계없이 호출되는 함수

class Song def duration_in_minutes @duration/60.0 # force floating point end def duration_in_minutes=(new_duration) @duration = (new_duration*60).to_i endendsong = Song.new("Bicylops", "Fleck", 260)song.duration_in_minutes 4.3333333song.duration_in_minutes = 4.2song.duration 252

song = Song.new(....) File.delete("doomed.txt")

Page 18: Ruby Language  입문 및 소개

– Class Method 정의» 크래스명 .메소드명 으로 선언함

• Singletons– 한 시스템에 해당 Class 에 대한 Object 는 오로지 하나만 존재하도록 하는 디자인 패턴의 하나

– new 함수를 private 으로 변경시킴– Object 생성은 따로 제공되는 method 를 통해서 이루어짐– Class Variable 에 Object 를 유지

class SongList MAX_TIME = 5*60 # 5 minutes def SongList.is_too_long(song) return song.duration > MAX_TIME end end song1 = Song.new("Bicylops", "Fleck", 260) SongList.is_too_long(song1)

class MyLogger private_class_method :new @@logger = nil def MyLogger.create @@logger = new unless @@logger @@logger endend

Page 19: Ruby Language  입문 및 소개

• Access Control– Public method : 누구나 호출할 수 있음– Protected method : 해당 클래스의 Object 와

서브클래스에서만 호출 가능– Private method : receiver 로 전달할 수가 없다 . 즉 , 자기

자신만 쓸 수 있다 . – 참고 1 : 다른 언어의 protected, private 과는 약간 다름– 참고 2 : variable 에는 access control 자체가 없다 . ( 무조건

private) 대신 attribute 개념이 있음 class MyClass def method1 # default is 'public' #... end protected # subsequent methods will be 'protected' def method2 # will be 'protected' #... end private # subsequent methods will be 'private' def method3 # will be 'private' #... end public # subsequent methods will be 'public' def method4 # and this will be 'public' #... end

class MyClass

def method1 end

# ... and so on

public :method1, :method4 protected :method2 private :method3 end

Page 20: Ruby Language  입문 및 소개

• Variable– Variable 은 Object 로의 reference 이다

person1 = "Tim" person2 = person1

person1[0] = 'J' person1 “Jim” person2 “Jim”

person1 = "Tim" person2 = person1.dup person1[0] = "J" person1 “Jim” person2 “Tim”

person1 = "Tim" person2 = person1 person1.freeze

person2[0] = "J“ 에러

Page 21: Ruby Language  입문 및 소개

Containers, Blocks, and Iterators

• Container : Object 의 Reference 를 담고 있음– Array 읽기

a = [ 1, 3, 5, 7, 9 ] a[2] 5 a[-1] 9 a[-2] 7 a[-99] nil

a = [ 1, 3, 5, 7, 9 ] a[1, 3] [3, 5, 7] a[3, 1] [7] a[-3, 2] [5, 7]

a = [ 1, 3, 5, 7, 9 ] a[1..3] [3, 5, 7] a[1...3] [3, 5] a[3..3] [7] a[-3..-1] [5, 7, 9]

• 잘못된 index : nil

• 음수 : Array 뒤부터• [ 시작 , 개수 ] : 시작 index 부터 개수만큼의 Array

• [ 시작 ..끝 ] : 시작부터 끝까지의 Array

• [ 시작 ..끝 ] : 시작부터 끝 하나 전까지의 Array

Page 22: Ruby Language  입문 및 소개

– Array 쓰기

a = [ 1, 3, 5, 7, 9 ]

a[2, 2] = ‘cat’ [1, 3, “cat”, 9]a[2, 0] = ‘dog’ [1, 3, “dog”, “cat”, 9]a[1, 1] = [9, 8, 7] [1, 9, 8, 7, “dog”, “cat”, 9]a[0..3] = [] [“dog”, “cat”, 9]a[5..6] = 99, 98 [“dog”, “cat”, 9, nil, nil, 99, 98]

• Size 를 넘어서는 index 에 쓰기 – 중간은 nil 로 채워짐

• [ 시작 , 개수 ] – 시작 index 부터 개수 만큼의 Array 부분을 새로운 Array 로 끼워넣음

• [ 시작 ..끝 ] – 시작부터 끝까지의 Array 부분을 새로운 Array 로 끼워넣음

• [ 시작 ...끝 ] – 시작부터 끝 하나 전까지 …

Page 23: Ruby Language  입문 및 소개

– Hash» Index 대신 key 를 이용하여 조회

• Block and Iterator– Block

» 기본적인 다른언어의 Block 개념 뿐 아니라 , » Method call 에 덧붙여 들어갈 수 있고 그 Block 은 con

text 를 유지한 채로 method 에 들어가 나중에 실행된다

h = { 'dog' => 'canine', 'cat' => 'feline', 'donkey' => 'asinine' }

h.length 3 h['dog'] “canine” h['cow'] = 'bovine‘ h[12] = 'dodecine' h['cat'] = 99 h { “cow” => “bovine”, “cat” => 99, 12=> “dodecine”, “donkey” => “asinine”, “dog” => “canine” }

Page 24: Ruby Language  입문 및 소개

– Block 을 이용한 Logic 과 Display 의 분리» fib_up_to 함수에는 logic 만 들어있다 .» Display 는 block 으로 받아들여 처리한다 .

– 다른 언어의 유사한 방식 (fuction pointer call-back, STL) 등에 비하여

» 전달 과정 및 수행 과정이 알기쉽고 투명하다» 전달하려는 Block 의 Context 를 전달할 수 있다

def three_times yield yield yield end three_times { puts "Hello" }

HelloHelloHello

def fib_up_to(max) i1, i2 = 1, 1 # parallel assignment (i1 = 1 and i2 = 1) while i1 <= max yield i1 i1, i2 = i2, i1+i2 endend

fib_up_to(1000) {|f| print f, " " }

1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987

Page 25: Ruby Language  입문 및 소개

– Block 을 이용한 Iterator 수행 예

[ 1, 3, 5, 7, 9 ].each {|i| puts i }

13579

["H", "A", "L"].collect {|x| x.succ } [“I”, “B”, “M”]

f = File.open("testfile") f.each do |line| puts line end f.close

첫재쭐…둘째줄…

[1,3,5,7].inject(0) {|sum, element| sum+element}16

[1,3,5,7].inject(1) {|product, element| product*element} 105

– 다른 언어의 Iterator 와의 차이점» External Iterator : Java 나 C++ 의 경우 외부의 Iterator 가

실제로 Iterate 시킬 객체를 control 한다» Internal Iterator : Ruby 는 객체 자신이 Iterate 를 시킨다

간단하고 투명하다 . Iteration 을 자신의 객체에 맞게 만들고 발전시킬 수 있다 .

Page 26: Ruby Language  입문 및 소개

• Block 과 Transaction– Transaction 을 표준화 시켜서 만들 수 있다 .

– 실제 Processing 하는 부분은 파일을 열고 닫기 위해 해야하는 작업을 알 필요가 없다

– 항상 파일이 Close 되는 것을 보장할 수 있다

class File def File.open_and_process(*args) f = File.open(*args) yield f f.close() end end

File.open_and_process("testfile", "r") do |file| while line = file.gets puts line end end

Page 27: Ruby Language  입문 및 소개

– Block 이 주어지지 않았을 때에는 그냥 File 객체를 리턴하도록 할 수도 있다 (Ruby-Style 의 구현임 )

class File def File.my_open(*args) result = file = File.new(*args) # If there's a block, pass in the file and close # the file when it returns if block_given? result = yield file file.close end

return result end end

Page 28: Ruby Language  입문 및 소개

• Closure– Block 의 실행 내용과 함께 해당 Block 의 Context( 참조가능

Method, 변수들 , Scope 등등의 모든 사항 ) 가 함께 전달되어 Block 을 전달받는 곳과 완전히 연결되는 Programming 언어적 방식

– 일반적인 구현방식

» 상속을 받고 , 해당 클래스에 구현한다» 버튼의 개수 만큼 클래스를 만들어야 할 것이다 .

class StartButton < Button def initialize super("Start") # invoke Button's initialize end def button_pressed # do start actions... endend

start_button = StartButton.new

Page 29: Ruby Language  입문 및 소개

– Closure 를 이용한 방식

» 버튼 생성시 해당 버튼이 동작해야할 내용을 함께 전달한다

» 클래스 내부에서는 songlist 라는 객체를 전혀 알 필요 없이 수행된다 ( 다른언어라면 어떻게 구현할 것인가 ? Songlist 객체 전달 ? Void* 전달 ? Songlist 가 아니라 다른 객체에 대한 구현을 할 때에는 ?)

» Subclassing 필요없이 , 하나의 클래스만으로 여러가지의 버튼을 만들어낼 수 있다 .

class JukeboxButton < Button def initialize(label, &action) super(label) @action = action end def button_pressed @action.call(self) endend

start_button = JukeboxButton.new("Start") { songlist.start }pause_button = JukeboxButton.new("Pause") { songlist.pause }

Page 30: Ruby Language  입문 및 소개

Standard Types

• Number– 물론 객체이다 .– Size제한 같은 것은 없다 .– Fixnum, Bignum 등이 내부적으로 있으며 변환은 자동으로

된다 .

• String– 내부적으로는 결국 8bit sequence 이다 .– 일본애들이 만든거라 code 문제도 고려되어 있다 .– 75 개 표준 method 가 함께 제공된다– Regular expression 과 함께 쓸 수 있기 때문에 상당히

강력하다

Page 31: Ruby Language  입문 및 소개

– Regular Expression, Hash 등을 이용해 색인 /검색기 구현– 마치 pseudo-code - 같다 .

» 짧고 간결하게 표현할 수 있다 .» natural 한 문장처럼 자연스럽게 쓰고 읽을 수 있다 . (Re

adability 와 Writability 가 함께 높다 )

class WordIndex def initialize @index = {} end def add_to_index(obj, *phrases) phrases.each do |phrase| phrase.scan(/\w[-\w']+/) do |word| # extract each word word.downcase! @index[word] = [] if @index[word].nil? @index[word].push(obj) end end end def lookup(word) @index[word.downcase] end end

Page 32: Ruby Language  입문 및 소개

• Range– 범위를 기본적인 자료형으로 가지고 있음– “..” : 맨 마지막 포함 , “…” : 맨 마지막 포함하지 않음– 다른 언어에서는 찾아볼 수 없는 Type– Sequence, condition, interval 3 가지로 사용됨

– Range as Sequence» Range operation 으로 sequence 생성

– Range as Condition» 앞의 조건이 만족하는 순간 부터 뒤의 조건이 만족하는 순간 까지 를 의미함

1..10 'a'..'z'

(1..10).to_a [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ('bar'..'bat').to_a [“bar”, “bas”, “bat”]

while line = gets puts line if line =~ /start/ .. line =~ /end/ end

Page 33: Ruby Language  입문 및 소개

– Interval» Case equality “===“ 를 이용하여 값이 범위에 들어가는

지 비교 가능 (in 의 의미 )

• Regular Expression– 언어에서 기본적으로 제공하는 Type 이다– Perl 처럼 강력하게 쓸 수 있고 , 객체 형식으로 이용할 수도

있다– 변수 만들기

(1..10) === 5 true (1..10) === 15 false (1..10) === 3.14159 true ('a'..'j') === 'c‘ true ('a'..'j') === 'z‘ false

a = Regexp.new('^\s*[a-z]')b = /^\s*[a-z]/c = %r{^\s*[a-z]}

Page 34: Ruby Language  입문 및 소개

– 사용 예 (substitution)

» 문자열 변환 , gsub 는 해당하는 모든 패턴» 문자열 a 는 변하지 않고 , 새로 변환된 문자열이

리턴되는 것임 ( 문자열 a 를 바꾸려면 sub! , gsub! 호출 )

» 단순 치환이 아니라 어떤 함수를 적용할 수 있음» 이럴 경우 바뀔 문자를 리턴하는 Block 을 던지면 끝 !

a = "the quick brown fox"a.sub(/[aeiou]/, '*') “th* quick brown fox"a.gsub(/[aeiou]/, '*') “th* q**ck br*wn f*x"a.sub(/\s\S+/, '') “the quick brown”a.gsub(/\s\S+/, '') “the”

a = "the quick brown fox"a.sub(/^./) {|match| match.upcase } “The quick brown fox”a.gsub(/[aeiou]/) {|vowel| vowel.upcase } “thE qUIck brOwn fOx”

Page 35: Ruby Language  입문 및 소개

Method• Logic 의 분리

– 덧셈 또는 곱셈을 1~10 까지 수행print "(t)imes or (p)lus: "times = getsprint "number: "number = Integer(gets)

if times =~ /^t/ puts((1..10).collect {|n| n*number }.join(", "))else puts((1..10).collect {|n| n+number }.join(", "))end

Interation 은 동일하지만 Logic 이 다르다는 이유로 똑같은 Display 를 두번하고 있음

print "(t)imes or (p)lus: "times = getsprint "number: "number = Integer(gets)

if times =~ /^t/ calc = lambda {|n| n*number }else calc = lambda {|n| n+number }endputs((1..10).collect(&calc).join(", "))

Block 에 담긴 Logic 을 변수에 저장해 전달Display 를 한번만 할 수 있음

Page 36: Ruby Language  입문 및 소개

Expression

• Ruby 에서 모든 문장은 Expression 이다 Object 가 리턴된다 .– if 문 case 문도 리턴한다– Return 이 없으면 마지만 문장이 리턴된다 song_type = if song.mp3_type == MP3::Jazz

if song.written < Date.new(1935, 1, 1) Song::TradJazz else Song::Jazz end else Song::Other end

rating = case votes_cast when 0...10 then Rating::SkipThisOne when 10...50 then Rating::CouldDoBetter else Rating::Rave end

Page 37: Ruby Language  입문 및 소개

• 모든 operation 은 method 다

• 몇 가지 새로운 비교연산자– “===“

» case 의 when 문에 쓰이는 연산자 . 속한다 포함된다는 의미이다– “<=>”

» Comparison 연산자 : 작다 , 같다 , 크다를 -1, 0, 1 로 만들어 리턴하는 연산자

– “eql?”» 값뿐만 아니라 type 도 비교한다 .» 1==1.0 은 true 하지만 1 eql? 1.0 은 false

– “equal?”» Object 가 만들어질때는 내부적으로 ID 가 부여되는데 , 이 ID 가

같은지 여부를 알 수 있음

(a*b)+c

와 아래문장은 동일 !!

(a.*(b)).+(c)

Page 38: Ruby Language  입문 및 소개

• Case 문 : 자연스러우면서도 강력함 – 내부적으로는 “ ===“ 연산자로 동작합

leap = case when year % 400 == 0: true when year % 100 == 0: false else year % 4 == 0 end

case input_line

when "debug" dump_debug_info dump_symbols when /p\s+(\w+)/ dump_variable($1) when "quit", "exit" exit else print "Illegal command: #{input_line}"end

case shape when Square, Rectangle # ... when Circle # ... when Triangle # ... else # ... end

kind = case year when 1850..1889: "Blues" when 1890..1909: "Ragtime" when 1910..1929: "New Orleans Jazz" when 1930..1939: "Swing" when 1940..1950: "Bebop" else "Jazz" end

String 비교 , Regex 비교 등이 자연스러움

Range 이용변수 없이 직접 조건을 넣어서

Class 의 경우 “ ===“ 는 해당클래스 , 또는 부모클래스의 Object 인지를 판단한다

Page 39: Ruby Language  입문 및 소개

• for … in– 다양한 Iterator 가 많기 때문에 for 문은 Ruby 에서 잘

사용되지 않는다

– each 만 구현하면 어느 객체던지 for in 을 돌릴 수 있다 .

• Loop 관련 예약어– break : Loop 탈출– next : 더 실행 안하고 다음 Loop 로 (continue)– redo : 더 실행 안하고 , 현재 상태에서 Loop 한번더– retry : Loop 를 완전 rollback 해서 처음부터 다시돌림

for i in ['fee', 'fi', 'fo', 'fum'] print i, " " end

for i in 1..3 print i, " " end

for song in songlist song.playend

위 문장은 사실 아래와 같다

songlist.each do |song| song.play end

Page 40: Ruby Language  입문 및 소개

• 사용자 정의 Loop

– do_until 은 마치 예약어처럼 보인다 .– block 을 던질 수 있기 때문에 (closure), 다른 언어에서는 sy

ntax 로 지원해야 하는 많은 기능들이 간단한 함수 정의로 구현된다 . Ruby 스타일 , Ruby 가 앞으로도 발전 /진화할 가능성이 많은 이유

def do_until(cond) break if cond yield retryend

i = 0

do_until(i > 10) do print i, " " i += 1 end

Page 41: Ruby Language  입문 및 소개

Exceptions• begin ~ end 사이에서 Exception 이 발생하면 rescue 문으로 해당 E

xception 객체와 함께 들어간다– Java 의 try ~ catch 와 비슷

– 참고 : Java 는 굉장히 엄격하게 , method 에서 Exception 관련사항을 정의하고 , 위에서는 잡아주고 해야하지만 Ruby 는 비교적 단순하다

op_file = File.open(opfile_name, "w") begin # Exceptions raised by this code will # be caught by the following rescue clause while data = socket.read(512) op_file.write(data) end

rescue SystemCallError $stderr.print "IO failed: " + $! op_file.close File.delete(opfile_name) raise end

Page 42: Ruby Language  입문 및 소개

– ensure » begin ~ end 사이에서 반드시 Exception 과 관계없이

실행되는 부분 . Java 의 finally 와 비슷– else

» rescue 에 들어가지 않은 경우 .. 즉 에러없이 성공적으로 끝냈을 때에만 들어가는 부분

– retry» 중간에 retry 명령을 만나면 begin 문 처음부터 다시 시작한다» 네트웍 에러시 재시도를 한다던지 알 수 있다

f = File.open("testfile") begin # .. process rescue # .. handle error else puts "Congratulations-- no errors!" ensure f.close unless f.nil? end

Page 43: Ruby Language  입문 및 소개

Module

• Module 은 Method, Class, Constant 등을 하나의 그룹으로 묶는 일을 한다– 모듈은 각각의 namespace 를 가진다

» 예를들어 C 는 다른 라이브러리를 include 하면 함수명이 충돌할 수 있다 . ( 그래서 C 에서는 큰 규모의 개발때 Naming 규칙을 정하는 것이 중요하다 )

» 하지만 Ruby 는 Module 내에서만 겹치지 않으면 된다

– 모듈을 이용하여 Mixin 을 구현할 수 있다» Ruby 에서는 Mixin 이란 개념을 이용하여 Multiple inhe

ritance 를 구현한다 .

Page 44: Ruby Language  입문 및 소개

• Mixin– 다른 클래스에 Module 을 밀어넣는 (include) 모듈– Ruby 에서는 다중상속을 금지하지만 , Mixin 을 이용하여

클래스의 기능을 확장할 수 있다

module Debug def who_am_i? "#{self.class.name} (\##{self.id}): #{self.to_s}" end end class Phonograph include Debug # ... end class EightTrack include Debug # ... end ph = Phonograph.new("West End Blues") et = EightTrack.new("Surrealistic Pillow") ph.who_am_i? “Phonograph (#945760): West End Blues et.who_am_i? “EightTrack (#945740): Surrealistic Pillow

Debug 모듈을 include 시켜서 두 클래스 모두 디버깅 기능을 가지게 되었음

그렇다고 Debug 클래스를 상속받은 것은 아님

Page 45: Ruby Language  입문 및 소개

– Comparable Module 을 include 시킴– “<=>” method 만 구현하면 나머지 연산은 자동으로 구현됨

class Song include Comparable def initialize(name, artist, duration) @name = name @artist = artist @duration = duration end def <=>(other) self.duration <=> other.duration endend

song1 = Song.new("My Way", "Sinatra", 225)song2 = Song.new("Bicylops", "Fleck", 260)

song1 <=> song2 -1song1 < song2 true song1 == song1 falsesong1 > song2 false

Page 46: Ruby Language  입문 및 소개

– Enumerable Module 을 include 시킴– “each” method 만 구현하면 나머지 연산은 자동으로 구현됨

class VowelFinder include Enumerable

def initialize(string) @string = string end

def each @string.scan(/[aeiou]/) do |vowel| yield vowel end endend

vf = VowelFinder.new("the quick brown fox jumped")

vf.inject {|v,n| v+n } “euiooue”

Page 47: Ruby Language  입문 및 소개

• Module include 와 C 언어의 include 가 다른점– C 는 모듈과 관계없이 단순히 physical 한 해당 파일을 포함

(include) 시키는 것이다 . 하지만 , Ruby 의 include 는 Logical 한 묶음이 포함되는 것이다 .

– Ruby 의 include 는 해당 모듈의 기능이 단순히 복사되어서 클래스에 합쳐지는 것이 아니다 . 클래스에서 include 된 모듈로의 Reference( 참조 ) 만 만들어지는 것이다

• Mixin 과 Java 의 Interface 가 다른점– Java 는 반드시 Abstract 해야 한다– Mixin 되더라도 원래의 클래스의 Type 이 변하는 것은

아니다 . 예를들어 해당 클래스가 Comparable Type 이 되는 것이 아니라 , “<=>”, “<“ 와 같은 메세지들을 처리할 수 있는 method 를 가지고 있는 함수가 되는 것이다 . (뒤쪽의 Duck Typing 참조 )

Page 48: Ruby Language  입문 및 소개

• method 명이 겹치면 ?– 실행될 method 는 우선순위에 의해 결정된다 . 자신 클래

스 , 자신이 가지고 있는모듈 , 상위 클래스 , 상위클래스의 모듈 등의 순

• 다른 파일 포함시키기– built-in 라이브러리가 아닌 , 다른 라이브러리에 들어있는

모듈을 사용할 때는 해당 라이브러리를 포함시켜야 한다– load : 해당 파일을 부를때 마다 다시 포함시킨다 .

» load ‘filename.rb’– require : 주로 require 를 사용한다 . 해당파일을 한번만 포함시킨다 . 확장자는 쓰지 않는다 .

» require ‘filename’

Page 49: Ruby Language  입문 및 소개

I/O

• I/O 관련된 함수들은 Kernel 이란 모듈에 대부분 구현되어있다 .– 참고 1 : Kernel 모듈은 Object 라는 클래스에 include

되어 있으므로 모든 클래스는 그 기능을 가지고 있다– 참고 2 : runtime 환경도 하나의 Object 이다 . 따라서 , put

c, puts 같은 것은 현재 자신 (runtime) 이 이미 가지고 있는 method 인 것이다

File.open("testfile") do |file| file.each_byte {|ch| putc ch; print "." }end

File.open("testfile") do |file| file.each_line {|line| puts "Got #{line.dump}" }end

Page 50: Ruby Language  입문 및 소개

• Networking– TCP, UDP, SOCKS, Unix Domain Socket 같은 것 기본으로

지원– HTTP, SOAP, FTP 관련 라이브러리 다양하게 구비하고 있음

require 'socket'

client = TCPSocket.open('127.0.0.1', 'finger') client.send("mysql\n", 0) # 0 means standard packet puts client.readlines client.close

require 'net/http'

h = Net::HTTP.new('www.pragmaticprogrammer.com', 80)

response = h.get('/index.html', nil)

if response.message == "OK" puts response.body.scan(/<img src="(.*?)"/m).uniq end

Page 51: Ruby Language  입문 및 소개

Ruby.inspect

Page 52: Ruby Language  입문 및 소개

Thread• Native Thread 를 직접 지원하지는 않음• Monitor 방식의 동기화 지원• 전체적으로 Java 와 비슷

– Thread.new (*args)» args 로 전달된 파라메터는 그대로 thread block 으로 전달된다

– thread block 은 local 을 보장한다– 만들어진 Thread 객체를 array 같은데 넣어두고 join 하던지 한다

require 'net/http'pages = %w( www.rubycentral.com slashdot.org www.google.com )threads = []for page_to_fetch in pages threads << Thread.new(page_to_fetch) do |url| h = Net::HTTP.new(url, 80) puts "Fetching: #{url}" resp = h.get('/', nil ) puts "Got #{url}: #{resp.message}" endendthreads.each {|thr| thr.join }

Page 53: Ruby Language  입문 및 소개

• Thread variable– 각 thread별 지역변수는 다른 thread 에서 접근 불가능– 만약 공유하고 싶으면 thread variable 로 넣으면 간단하게

공유된다» “[ ] =“ 메소드로 구현 : 스레드오브젝트 [ 키 ] = 값

• Control – Thread.stop : 멈춤– Thread.run : 시작– Thread.pass : 다른 thread 에게 schedule 을 넘겨줌

count = 0 threads = [] 10.times do |i| threads[i] = Thread.new do sleep(rand(0.1)) Thread.current["mycount"] = count count += 1 end end threads.each {|t| t.join; print t["mycount"], ", " } puts "count = #{count}"

Page 54: Ruby Language  입문 및 소개

• Mutual Exclusion : Monitor 를 이용하여 해결– Subclassing : Monitor Class 를 Subclassing

– Mixin : MonitorMixin 모듈을 include

require 'monitor'class Counter < Monitor attr_reader :count def initialize @count = 0 super end def tick synchronize do @count += 1 end endend

require 'monitor'

class Counter include MonitorMixin# . . .end

Page 55: Ruby Language  입문 및 소개

– External Monitor : 외부의 Monitor 객체 이용» Monitor 객체에 동기화 되어야하는 Block 을 던짐» Counter 기준이 아니라 Monitor 객체별로 동기화를

수행할 수 있음» 여기서 보듯 , synchronize 는 syntax 가 아니라 함수임

require 'monitor'

class Counter attr_reader :count def initialize @count = 0 end def tick @count += 1 endend

c = Counter.newlock = Monitor.new

t1 = Thread.new { 10000.times { lock.synchronize { c.tick } } }t2 = Thread.new { 10000.times { lock.synchronize { c.tick } } }t1.join; t2.join #!sh!

Page 56: Ruby Language  입문 및 소개

– Extend 이용» 전혀 동기화 기능이 없는 Object 에 동적으로 Mixin

모듈을 집어 넣음» Counter 클래스의 다른 객체는 동기화 기능이 없고 , 오직 이 객체에만 동기화 기능이 동적으로 덧붙여짐

require 'monitor'

class Counter # as before...end

c = Counter.newc.extend(MonitorMixin) #!sh!

t1 = Thread.new { 10000.times { c.synchronize { c.tick } } }t2 = Thread.new { 10000.times { c.synchronize { c.tick } } }

t1.join; t2.join #!sh!c.count

Page 57: Ruby Language  입문 및 소개

• Process– sub process fork 시키고 , pipe 연결하고 , signal 처리하고

등등 할 수 있음

trap("CLD") do pid = Process.wait puts "Child pid #{pid}: terminated" end

exec("sort testfile > output.txt") if fork.nil?

# do other stuff...

fork do puts "In child, pid = #$$" exit 99 end pid = Process.wait puts "Child terminated, pid = #{pid}, status = #{$?.exitstatus}"

Page 58: Ruby Language  입문 및 소개

Unit Testing

• 최근 개발방법론 중 하나로 굉장히 중요하게 대두되고 있음– XUnit, JUnit 등… Test Driven Development

• 좋은점– 코딩전 : 정확히 돌아가는 지 개발중에 즉시 feedback 을

받을 수 있다– 코딩후

» 개발이 끝난 후에 , 환경이 바뀌거나 시간이 흐른 후에도 여전히 잘 돌아가는지 확인할 수 있다

» 다른사람이 코드를 이해할 수 있는 예제가 될 수 있다

• Ruby 의 구현방법– 표준 라이브러리인 Test::Unit::TestCase 를 상속받아 테스트 클래스를 만든다

– 테스트 method 명이 test 로 시작해야 한다

Page 59: Ruby Language  입문 및 소개

• 준비된 assert_ 메소드 들로 나와야할 결과 확인

• 테스트 결과

– 개발 디렉토리와 동일한 구조를 가지는 test 디렉토리에 위와같은 테스트 Unit 을 넣고 테스트 함

– 라이브러리와 함께 배포할 수 있음

#require 'roman'require 'test/unit'class TestRoman < Test::Unit::TestCase

def test_roman assert_equal("iii", Roman.new(3).to_s) assert_equal("iv", Roman.new(4).to_s) assert_raise(RuntimeError) { Roman.new(0) } assert_nothing_raised() { Roman.new(1) } assert_nothing_raised() { Roman.new(499) } assert_raise(RuntimeError) { Roman.new(5000) } endend

Loaded suite –Started.Finished in 0.003655 seconds.

1 tests, 6 assertions, 0 failures, 0 errors

Page 60: Ruby Language  입문 및 소개

Tools

• Debugger– Ruby Interpreter 에 내장되어 있음 – r debug 옵션으로 돌리면 됨

– -r debug 옵션으로 돌리면 특정 전역변수에 셋팅되어 알 수 있음

• Interactive Ruby, irb– Ruby 명령어를 한 줄 한 줄 넣어가며 개발 , 테스트 해 볼 수

있음 . 교육 , 테스트시 유용함• Editor : emacs, vi 등과 붙여서 개발환경 만들 수 있음• Benchmark

– Benchmark 표준 모듈 이용– block 을 잡아서 이름 붙이고 시간을 잴 수 있음

• Profiler– profiler 라이브러리를 읽어 들이기만 하면 됨– 아니면 ruby 실행시 – r profile 옵션을 주면 됨

Page 61: Ruby Language  입문 및 소개

Benchmark 의 수행 및 출력결과

Profiler 수행결과

Page 62: Ruby Language  입문 및 소개

• RDoc– 정해진 약속대로 주석을 달면 적절한 Document 가 생성됨– javadoc 과 비슷– API Document, 프로그램 usage 등…

• RubyGems– Ruby 의 표준 패키지 관리 Tool

» 표준 패키지 포맷» 이 포멧으로 중심 Repository 구현» 한가지 라이브러리의 여러버전 별 설치 및 관리가 가능» End user 의 패키지 검색 , 설치 , 제거 , 제작배포 등의

도구가 들어있음– 패키지 가져오기

» 원하는 버전에 맞추어서» API Document 같은 것도 같이 온다

% gem install –r rake –v “< 0.4.3”Attempting remote installation of ‘rake’Successfully installed rake, version 0.4.2% rake –versionrake, version 0.4.2

Page 63: Ruby Language  입문 및 소개

– 패키지 사용하기

– 패키지 만들기

require 'rubygems'require_gem 'BlueCloth', '>= 0.0.5‘

require 'rubygems'

SPEC = Gem::Specification.new do |s| s.name = "MomLog" s.version = "1.0.0" s.author = "Jo Programmer" s.email = "[email protected]" s.homepage = "http://www.joshost.com/MomLog" s.platform = Gem::Platform::RUBY s.summary = "An online Diary for families" candidates = Dir.glob("{bin,docs,lib,tests}/**/*") s.files = candidates.delete_if do |item| item.include?("CVS") || item.include?("rdoc") end s.require_path = "lib" s.autorequire = "momlog" s.test_file = "tests/ts_momlog.rb" s.has_rdoc = true s.extra_rdoc_files = ["README"] s.add_dependency("BlueCloth", ">= 0.0.4")end

잠깐 !!!

Spec 정의하는 Constructor 의입력은 block 임

initialize 는 default 값을집어넣고 , 여기서는실제 값을 assign 함

다른 언어에서는 찾아보기힘든 Constructor

Page 64: Ruby Language  입문 및 소개

– 실행 파일들 , 문서 , 테스트 파일 , 관련 C 파일 까지 합쳐서 배포할 수 있다

– 배포할 패키지가 필요로 하는 다른 패키지를 정의할 수 있다» s.add_dependency("BlueCloth", ">= 0.0.4")» 이렇게 하면 설치할 때 BlueCloth 패키지는 자동으로

설치한다– C 파일을 함께 배포한다면 mkmf 를 이용해 각 machine 에 맞게 컴파일 하도록 배포할 수 있으며 , dll 같은 바이너리를 직접 배포할 수도 있다

– 참고 : Ruby 에서는 패키지를 “ gem” 이라고 부름

Page 65: Ruby Language  입문 및 소개

Ruby and the Web• CGI 라이브러리가 표준 라이브러리에 있음

• Template 시스템 당연히 있음– Rdoc template, amrita– eRuby : erb, eruby 주로 쓰임– apache 에 module 로 설치가능 : .rhtml

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"><html><head><title>eruby example</title></head><body><h1>Enumeration</h1><ul>%5.times do |i| <li>number <%=i%></li>%end</ul><h1>"Environment variables starting with "T"</h1><table>%ENV.keys.grep(/^T/).each do |key| <tr><td><%=key%></td><td><%=ENV[key]%></td></tr>%end</table></body></html>

Loop 가 간결하다

맨앞이 %로 시작하면 Ruby 코드이다

<% 부터 %> 도 Ruby 코드

Page 66: Ruby Language  입문 및 소개

• Ruby 웹서버 : 100% Ruby 웹서버– 웹서버 띄우기

#!/usr/bin/rubyrequire 'webrick'include WEBrick

s = HTTPServer.new( :Port => 2000, :DocumentRoot => File.join(Dir.pwd, "/html"))

trap("INT") { s.shutdown }

s.start

Page 67: Ruby Language  입문 및 소개

• Servlet 컨테이너

#!/usr/bin/ruby

require 'webrick'include WEBrick

s = HTTPServer.new( :Port => 2000 )

class HelloServlet < HTTPServlet::AbstractServlet def do_GET(req, res) res['Content-Type'] = "text/html" res.body = %{ <html><body> Hello. You're calling from a #{req['User-Agent']} <p> I see parameters: #{req.query.keys.join(', ')} </body></html> } endend

s.mount("/hello", HelloServlet)

trap("INT"){ s.shutdown }

s.start

Page 68: Ruby Language  입문 및 소개

• SOAP and Web Service– 표준라이브러리를 이용해서 Client, Server 를 간단히 제작할 수 있다

– 구글에 접속하여 검색결과를 받아오는 예

require 'soap/wsdlDriver'require 'cgi'

WSDL_URL = "http://api.google.com/GoogleSearch.wsdl"

soap = SOAP::WSDLDriverFactory.new(WSDL_URL).createDriver

query = 'pragmatic'key = File.read(File.join(ENV['HOME'], ".google_key")).chomp

result = soap.doGoogleSearch(key, query, 0, 1, false, nil, false, nil, nil, nil)

printf "Estimated number of results is %d.\n", result.estimatedTotalResultsCount

printf "Your query took %6f seconds.\n", result.searchTimefirst = result.resultElements[0]puts first.titleputs first.URLputs CGI.unescapeHTML(first.snippet)

Page 69: Ruby Language  입문 및 소개

• Rails– Ruby on Rails 라고 잘 알려져 있다– 특징

» Ruby 로 만들어진 open source Web application framework» MVC (Model-View-Controller) 아키텍쳐를 제대로 구현했다는 평가를 받고 있다 . Ruby 의 많은 언어적 특징이 이를 가능하게 해준다

» 엄청나게 빠른 개발속도» 이미 다양한 라이브러리가 많이 존재한다 .

– 2005 년 12월에 version 1.0 나옴 .– Rails 때문에 최근들어 Ruby 라는 언어가 조명받고 있음– 구조

» Model : OOP 기반의 database-driven 웹 애플리케이션을 대상으로 한다 . 데이터 모델링만 하면 현존하는 RDBMS 들과 자동으로 강력하게 연동을 한다

» View : Display 를 담당 . eRuby 이용하여 최종 html 생성해냄 . Ajax 관련 기능이 들어있다

» Controller : Logic 에 해당하는 부분 . Web browser 로 시작되는 사용자의 action 을 받아 최종적인 View 로의 데이터 전달까지를 담당한다

– 참고서적 : Agile Web Development with Rails

Page 70: Ruby Language  입문 및 소개

Duck Typing

• Ruby 는 “ Class 는 Type 이 아니다” 라는 사상에 기초하고 있다 .

• C, C++, Java 와 같은 Language 는 Strong Type Checking 을 하지만– 그러면 왜 Java 에서 ClassCastException 을 사용하고 , O

bject 라는 클래스를 사용할까 ?– C 의 경우 void* 없이 코딩할 수 있는가 ?

• Ruby 는– type safety 라는 성질이 language 가 safe 하다는 것과는

다르다고 생각한다 . – 안전하면서도 Productive 한 방법으로 type 문제를

해결한다

Page 71: Ruby Language  입문 및 소개

• Duck Typing– 명칭

» 뒤뚱거리면서 걷고 , 꾁꾁하고 울면 그건 오리다» 굳이 오리인지 아닌지 피검사하고 그럴 필요가 있겠는가…

» Smalltalk, Visual FoxPro, Coldfusion 등의 언어에서 사용된 개념

– Class 의 type 을 체크하는 것이 아니라 , Class 가 어떤 행동을 할 수 있는 지만 알면 된다

– Strong type checking 으로 구현한다면def append_song(result, song) # test we're given the right parameters unless result.kind_of?(String) fail TypeError.new("String expected") end unless song.kind_of?(Song) fail TypeError.new("Song expected") end result << song.title << " (" << song.artist << ")"end

result = ""append_song(result, song)

Page 72: Ruby Language  입문 및 소개

– 하지만 , Ruby 에서는 그냥 쓴다

– 굳이 안전하게 검사를 하자면

» “<<“, “artist”, “title” 이란 method 를 지원하는지를 검사한다 . 하지만 실용적인 (pragmatic) 의미에서 별로 필요 없다

def append_song(result, song) result << song.title << " (" << song.artist << ")"end

result = ""append_song(result, song)

def append_song(result, song) # test we're given the right parameters unless result.respond_to?(:<<) fail TypeError.new("'result' needs `<<' capability") end unless song.respond_to?(:artist) && song.respond_to?(:title) fail TypeError.new("'song' needs 'artist' and 'title'") end result << song.title << " (" << song.artist << ")"end

result = ""append_song(result, song)

Page 73: Ruby Language  입문 및 소개

• Conversion– 다른 언어에서는 그냥 자동으로 casting 되거나 , 명시적으로

casting 해서 사용하지만 , Ruby 에서는 casting 이 없다– Ruby 는 정교한 conversion protocol 로 해결한다

» Not Strict Conversion : to_i, to_s 같은 Method 해당 Object 를 그냥 String 으로 표현하는 것이지 ,

그것을 String 으로 간주하고 변환해서 어떤작업을 해야하는 것은 아니다

» Strict Conversion : to_int, to_str, to_ary 등의 Method 해당 Object 가 String 으로 변환되어 자연스럽게

사용될 수 있는 경우» Numeric Coersion

1 + 2.3 에서 casting 은 어떻게 일어날까 ? 자동으로 ? 자신과 다른 Object 와의 Numeric 연산을 할때는 , c

oerce 라는 함수를 interpreter 가 불러서 동일한 Type으로 변환시켜 최종 연산을 한다

명시적이고 , 투명하고 , 사용자 정의 가능하고…

Page 74: Ruby Language  입문 및 소개

• 저자의 Duck Typing 에 대한 변– 일단 마음을 열고 Duck Typing 을 해봐라 . 의외로

에러투성이의 코드가 나온다던 지 하는 일들이 발생하지 않는다 ( 우리는 속아 살았나 ? )

– 경험으로는 오히려 훨씬 안전하고 Productive 한 방식이다– 그리고 , 사실 이것은 코딩 스타일이지 , 규칙은 아니다 .

Page 75: Ruby Language  입문 및 소개

Classes and Objects In Ruby

• Ruby 에서 Class, Object 의 내부 구조는 ?– Object 는 flag, variable, 그리고 관련 Class 정보를

가지고 있다 .– 클래스는 Class 라는 클래스의 Object 이고 , method tabl

e 과 superclass 로의 reference 를 가지고 있다 .– method call 은 대상 receiver 를 후보로 두고 , 그 method

를 가지고 있는 놈을 우선순위를 두고 찾는다 . 우선 , 대상 클래스에서 찾고 , 없으면 module, 없으면 , 부모클래스 , 없으면 부모클래스의 모듈… 이런 식으로 찾는다

Page 76: Ruby Language  입문 및 소개

• 기본적인 Object, 클래스와 부모 클래스

Page 77: Ruby Language  입문 및 소개

• 클래스 method 를 가지고 있는 클래스는 meta 클래스가 만들어지며 거기에 클래스 method 가 구현된다

Page 78: Ruby Language  입문 및 소개

• Object-specific 클래스 (Object 자체에 클래스의 기능을 동적으로 확장하는 Object 만의 클래스 ) 는 가상 클래스를 동적으로 만들어 구현한다

Page 79: Ruby Language  입문 및 소개

• 모듈이 include 될 때 (Mixin) 는 실제 Module 이 들어가는 것이 아니라 Proxy 클래스라는 가상의 클래스가 생기고 , 이 클래스는 module 로의 레퍼런스만 가지고 있다 . (따라서 , 만약 모듈이 변경된다면 , 이 모듈을 참조하는 모든 클래스도 함께 영향 받음 )

Page 80: Ruby Language  입문 및 소개

• Cache 기능 구현하기– 어떤 값을 조회할때 많은 계산이 필요하다면 , 한번만 계산하고 이후에는 그 값을 계속 사용하고 싶다면 ?

– 아래는 일반적인 Cache 구현 class ExampleDate def initialize(day_number) @day_number = day_number end def as_day_number @day_number end def as_string unless @string # complex calculation @string = result end @string end def as_YMD unless @ymd # another calculation @ymd = [ y, m, d ] end @ymd end # ... end

Page 81: Ruby Language  입문 및 소개

– 아래와 같이 once 라는 것이 있어서 자동으로 cache 가 되면 좋을 텐데…

class ExampleDate def as_day_number @day_number end def as_string # complex calculation end def as_YMD # another calculation [ y, m, d ] end

once :as_string, :as_YMD end

Page 82: Ruby Language  입문 및 소개

– 아래와 같이 실제로 once 를 만들 수 있음 !

» Method 를 가로채는 기능인 alias_method 라는 기능과 , eval 이 있어서 가능

» eval : eval 에 들어가는 문자열을 실제 코드로 실행해 줌– 토의

» 실제로 앞에서 살펴봤던 , attr_reader, attr_writer, private_class, 심지어 private, protected 하는 것 등등의 많은 것들이 once 와 같은 함수에 불과 하다 .

» 다른 언어였으면 syntax 로 지원 되어야만 하는 기능을 Ruby는 얼마든지 만들어 낼 수 있다 . 이런 것이 Readability 와 Writability 를 좋게 해주는 비결일 것이다 .

def once(*ids) # :nodoc: for id in ids module_eval <<-"end;" alias_method :__#{id.to_i}__, :#{id.to_s} private :__#{id.to_i}__ def #{id.to_s}(*args, &block) (@__#{id.to_i}__ ||= [__#{id.to_i}__(*args, &block)])[0] end end; end end

Page 83: Ruby Language  입문 및 소개

• freezing– Object 가 너무 동적이고 그래서 위험하지 않을까 ?– freeze 라는 method 를 호출하면 , Object 의 상태는 다시는

변할 수 없다– 하지만 의외로 별로 쓸일이 없다 .

Page 84: Ruby Language  입문 및 소개

Etc…

• Locking– Taining 이란 개념 이용 : Safe Level 로 내부 리소스 접근 권한 제어

– 만약 누군가 위의 expr 에 “ system(“rm *”) 라고 넣었다면 ?– expr 은 외부에서 들어온 변수이므로 tained 되어 처리된다

require 'cgi' cgi = CGI.new("html4") # Fetch the value of the form field "expression" expr = cgi["expression"].to_s begin result = eval(expr) rescue Exception => detail # handle bad expressions end # display result back to user...

Page 85: Ruby Language  입문 및 소개

• Dynamic method calling– C 라면 아래와 같이 구현… typedef struct { char *name; void (*fptr)(); } Tuple;

Tuple list[]= { { "play", fptr_play }, { "stop", fptr_stop }, { "record", fptr_record }, { 0, 0 }, };

...

void dispatch(char *cmd) { int i = 0; for (; list[i].name; i++) { if (strncmp(list[i].name,cmd,strlen(cmd)) == 0) { list[i].fptr(); return; } } /* not found */ }

Page 86: Ruby Language  입문 및 소개

– Ruby 라면 그냥 해당 오브젝트에 메시지를 보내면 됨» eval 함수가 지원되므로 당연히 구현할 수 있을 것임» commands.send(command_string) 형식

– 심지어는 eval 될 문장과 binding될 context까지 전달할 수 있음

"John Coltrane".send(:length) "Miles Davis".send("sub", /iles/, '.')

def get_a_binding val = 123 bindingend

val = "cat"

the_binding = get_a_bindingeval("val", the_binding) 123eval("val") “cat”

Page 87: Ruby Language  입문 및 소개

• System Hook– new 를 aliasing 으로 가로채서 모든 Object 가 만들어질 때

마다 만들어진 시간을 남기는 기능

– Ruby 의 모든 클래스의 메소드들이 이렇게 동적으로 aliasing, 변경 , 확장 가능하므로 무한히 많은 일을 할 수 있다

class Object attr_accessor :timestamp end

class Class alias_method :old_new, :new def new(*args) result = old_new(*args) result.timestamp = Time.now result end end

Page 88: Ruby Language  입문 및 소개

• Marshaling– Object 의 상태를 저장하고 , 그것을 다시 읽어서 Object 를

생성하는 기능– Serialization 이라고도 함– Marshal.dump, Marshal.load

» File 에 binary 로 marshaling 하는 method– marshal_dump, marshal_load 를 구현하면 사용자 정의 m

arshaling 을 할 수 있다• YAML for Marshaling

– Binary 는 Ruby 의 버전에 따라 달라질 수 있고 , distributed 하게 serialization 할 때 문제가 될 수 있음

– Text 형태로 저장하고 읽고 할 수 있음– What is YAML?

» YAML 은 YAML Ain’t Markup Language 의 약자» Human readable + Machine readable» 객체 Serialization 과 Config 설정 등에 주로 쓰임» http://www.yaml.org 참조

Page 89: Ruby Language  입문 및 소개

• Distributed Ruby– 내장된 라이브러리를 이용하여 간단하게 분산환경 구성 가능– 분산 Ruby 서버

– 분산 Ruby 클라이언트

require 'drb'

class TestServer def add(*args) args.inject {|n,v| n + v} endend

server = TestServer.newDRb.start_service('druby://localhost:9000', server)DRb.thread.join # Don't exit just yet!

require 'drb'DRb.start_service()obj = DRbObject.new(nil, 'druby://localhost:9000')# Now use objputs "Sum is: #{obj.add(1, 2, 3)}"

Page 90: Ruby Language  입문 및 소개

마 무 리

• Dynamic 한 언어– 언어적 특징도 Dynamic 하고– 굉장히 빠르게 발전하고 , 앞으로의 발전 가능성도 많음

• 균형잡힌 언어– 우아하지만 실용적이지 못했던 많은 OOP 개념을 실제로

적용하였음 : 타 언어 개발자도 공부할 가치가 많음– 하지만 , 굉장히 실용적으로 만들어 내는데 성공한 듯 :

엄청나게 빠른 개발속도로 인정받고 있음

• 재미있는 언어– 남의 코드를 보면서 , 코딩을 하면서 참 재미있음– 워낙 재미 있어서 인지 Ruby 에 참여하고 개발하는 사람이

상당히 많고 활동도 활발함– 완전 Open Source!! Binary 가 없으니까… 비밀은 없음