(본 게시물은 저작권의 문제 발생시 출판사의 요청에 의해 삭제될 수 있습니다.)
(이전 포스팅 내용 이어서) 컨테이너는 어디에나 있다
컨테이너, 블록, 반복자는 루비의 핵심 개념이다. 루비 코드를 작성하면 할수록 전통적인 반복문을 벗어나는 자신을 발견하게 될 것이다. 대신 자신의 내용을 반복하는 것을 돕는 클래스를 작성하게 된다. 이런 코드가 간결하고 읽기 쉽고, 또 관리도 편하다는 사실도 금방 깨닫게 될 것이다.
루비 라이브러리들과 프레임워크를 사용하는 과정에서 자연스럽게 많은 연습을 하게 될 것이다.
상속과 메시지
to_s 를 구현하지 않은 클래스의 객체들도 to_s 메서드 호출에 대해 무언가를 반환해준다. 이것이 어떻게 가능한지 이해하려면 상속과 자식 클래스 생성, 그리고 루비에서 객체가 메시지를 받았을 때 어떤 메서드를 실행할지 결정하는 방법을 이해해야 한다.
자식 클래스를 생성하는 기본적인 원리는 간단한다. 먼저 자식 클래스는 부모 클래스의 모든 기능을 상속한다. 자식 클래스에서 부모 클래스의 모든 인스턴스 메서드를 사용할 수 있다.
먼저 간단한 예제를 살펴보자.
class Parent
def say_hello
puts "Hello from #{self}"
end
end
p = Parent.new
p.say_hello
# 자식 클래스 생성
class Child < Parent
end
c = Child.new
end
c = Child.new
c.say_hello
실행결과
Hello from #<Parent:0x007fcd59034c78>
Hello from #<Child:0x007fcd59034908>
< 문법은 오른쪽에 있는 클래스를 부모로 하는 새로운 클래스를 정의한다는 의미이다. 더 작다는 의미를 가진 < 기호는 자식 클래스가 부모 클래스를 더 특수화했다는 것을 의미한다. Child는 아무런 메서드가 없지만 Child 클래스에서 인스턴스를 만들면 이 인스턴스는 say_hello 메소드를 사용할 수 있다.
superclass 메서드는 수신자(특정 클래스)의 부모 클래스를 반환한다.
class Parent
end
class Child < Parent
end
Child.superclass # => Parent
그런데 Parent 클래스에도 부모 클래스가 있을까?
class Parent
end
Parent.superclass # => Object
클래스를 정의할 때 부모 클래스를 지정하지 않으면 루비는 자동으로 내장 클래스인 Object를 그 클래스의 부모로 삼는다. 그럼 Object의 부모를 찾아보자.
Object.superclass # => BasicObject
BasicObject 클래스는 메타프로그래밍에 사용되는 클래스로 아무것도 없는 캔버스 처럼 작동한다. BasicObject 에도 부모 클래스가 있을까?
BasicObject.superclass.inspect # => "nil"
루비 애플리케이션의 어떤 객체라도 부모의 부모의 부모의 뿌리를 찾아가다 보면 결국에는 BasicObject에 이른다. 루비는 자기 자신에 정의되어 있지 않은 메서드를 자신의 부모 클래스에서 찾고, 여기서도 없으면 부모의 부모 클래스에서 찾고, 이렇게 부모 클래스가 더 이상 없을 때까지 메서드를 찾아나간다.
to_s 메서드는 Object 클래스에 정의되어 있다. Object 클래스는 BasicObject를 제외한 모든 클래스의 부모 클래스이므로 루비의 어떤 클래스의 인스턴스라도 to_s 메서드가 정의되어 있다.
class Person
def initialize(name)
@name = name
end
end
p = Person.new("Michael")
puts p
실행결과
#<Person:0x007fc812839550>
to_s 메서드를 오버라이드 해보자.
class Person
def initialize(name)
@name = name
end
def to_s
"Person named #{@name}"
end
end
p = Person.new("Michael")
puts p
실행결과
Person named Michael
루비 온 레일즈를 사용하면 자신만의 컨트롤러 클래스 정의를 위해 ActionController를 상속할 것이다. 이를 통해 자신의 컨트롤러에서 ActionController의 모든 기능을 사용할 수 있으며 추가적으로 사용자의 요청에 대응할 수 있는 고유의 핸들러를 사용할 수 있다.
끄읕