메서드 탐색 경로와 관련하여 좀 더 독특한 경우가 있는데, 그것을 살펴보기 위해서는 믹스인을 다시 들여다볼 필요가 있다.
믹스인은 다중 상속의 복잡한 문제 없이 클래스나 모듈이 다른 모듈의 메서드를 가져와 사용할 수 있도록 해주는 기능이다.
Array, Hash, Range 등 여러 클래스들이 Enumerable 모듈을 인클루드함으로써 믹스인의 혜택을 누리고 있다.
모듈을 믹스인하는 방법에는 include, prepend, extend 메서드를 사용하는 방법이 있는데, 우선 include와 prepend를 비교해 보자.
아래 그림을 보면 foo 메서드 하나를 정의한 모듈 M이 있고 클래스 C1과 C2는 include를 사용하여 모듈 M을 믹스인 했고 클래스 C3는 prepend를 사용하여 모듈 M을 믹스인 했다.
그 결과 ancestors 메서드의 결과를 보면 클래스 C1과 C2의 메서드 팀색 경로에서는 C1과 C2 다음에 모듈 M이 나오고 클래스 C3의 메서드 탐색 경로에서는 C3보다 모듈 M이 먼저 나온다.
따라서, 클래스 C1과 C2의 객체에 대해 메서드를 호출하면 해당 메서드를 자신의 클래스에서 먼저 찾아보고 없으면 모듈 M에서 찾지만,
클래스 C3의 객체에 대해 메서드를 호출한 경우에는 모듈 M에서 먼저 찾고 없으면 클래스 C3에서 찾는다.
C1, C2, C3 클래스의 객체에 대해 foo 메서드를 호출한 결과가 방금 설명한 메서드 탐색 경로에 맞게 잘 나온 것을 볼 수 있다.
extend는 모듈을 대상 객체의 싱글톤 클래스에 인클루드 시킨다. 그래서 클래스에 대해 모듈을 extend 하면 해당 모듈의 인스턴스 메서드를 대상 클래스의 클래스 메서드처럼 호출할 수 있게 되는 것이다.
아래 그림을 보면 클래스 C에 모듈 M을 extend로 믹스인할 때 클래스 C의 싱글톤 클래스가 생성되는 것을 알 수 있다. (싱글톤 클래스의 개수가 하나 증가했다.)
그리고 실제 클래스 C에 대해 singleton_methods 메서드를 호출해 보면 foo 메서드가 보인다. 그러나 인수를 false로 주고 singleton_methods 메서드를 호출해 보면 빈 배열이 나오는데, foo 메서드가 클래스 C에서 직접 정의한 클래스 메서드가 아니기 때문이다.
또한 클래스 C의 싱글톤 클래스에 대해 ancestors 메서드를 호출해 보면 메서드 탐색 경로 상에서 C의 싱글톤 클래스(#<Class:C>) 다음에 모듈 M이 위치하고 있는 것을 볼 수 있다.
따라서, 클래스 C에 대해 클래스 메서드를 호출하면 해당 메서드를 클래스 C의 싱글톤 클래스에서 먼저 찾아보고 없으면 모듈 M에서 찾게 된다.
그렇다면 클래스 C를 상속하는 클래스 C2가 있을 때 클래스 C2에서도 클래스 메서드 foo를 호출할 수 있을까?
아래 그림을 보면 바로 답을 알 수 있다.
C2.singleton_class.ancestors의 결과를 보면 C2의 싱글톤 클래스(#<Class:C2>)가 C1의 싱글톤 클래스(#<Class:C>)를 상속하고 있는 게 보인다.
그리고 여전히 C1의 싱글톤 클래스는 모듈 M을 인클루드 하고 있다.
따라서 클래스 C2에 대해 foo 메서드를 호출하면 C2의 싱글톤 클래스에서 먼저 찾아보고 없으면 C1의 싱글톤 클래스에서 찾고 그래도 없으면 모듈 M에서 찾게 된다.
즉, 어떤 클래스에서 호출 가능한 클래스 메서드는 그 클래스의 하위 클래스에서도 호출할 수 있다는 것을 알게 되었다.
결국, 클래스 메서드는 싱글톤 클래스의 입장에서 보면 인스턴스 메서드일뿐이고 인스턴스 메서드는 서브 클래스로 상속되기 때문이다.
extend를 사용해 모듈을 믹스인하는 것이 클래스로만 한정되는 것은 아니다.
아래 그림을 보자.
클래스 C의 객체를 하나 생성하여 변수 c에 할당한 후 바로 c에 대해 foo 메서드를 호출하면 클래스 C에서 정의한 foo 메서드가 실행되지만,
c에 대해 extend 메서드를 사용하여 모듈 M을 믹스인 한 후 다시 foo 메서드를 호출해 보면 모듈 M에서 정의한 foo 메서드가 실행되는 것을 볼 수 있다.
그리고 c.singleton_class.ancestors의 결과를 보면 모듈 M을 믹스인 한 후 메서드 탐색 경로에 모듈 M이 객체 c의 싱글톤 클래스 바로 다음에 위치하게 된 것을 볼 수 있다.
즉, c에 대해 foo 메서드를 호출하면 클래스 C 보다 모듈 M에서 먼저 foo 메서드를 찾는 것이다.
See you again~