티스토리 뷰

객체로서의 블록


블록은 익명 메서드와 비슷하지만 단순히 이걸로 끝이 아니다. 블록은 객체로 변환할 수 있으며, 이 객체를 변수에 저장할 수도 있고, 어딘가에 넘겨줄 수도 있으며, 나중에 호출할 수도 있다.


블록은 메서드에 넘겨지는 추가적인 매개변수로 생각해도 무방하다. 사실 암묵적인 매개 변수일 뿐만 아니라 명시적인 매개변수로 사용할 수 있다. 메서드를 정의할 때 마지막 매개 변수에 앰퍼샌드(&)를 접두사로 붙이면 루비는 이 메서드가 호출될 때마다 코드 블록이 넘겨졌는지 찾아본다. 


다음은 특정 인스턴스 메서드에서 Proc 객체를 생성하고 이를 인스턴스 변수에 저장하고, 다른 인스턴스 메서드에서 이를 호출하는 예제다.


1
2
3
4
5
6
7
8
9
10
11
12
class ProcExample
    def pass_in_block(&action)
        @stored_proc = action
    end
    def use_proc(parameter)
        @stored_proc.call(parameter)
    end
end
 
eg = ProcExample.new
eg.pass_in_block { |param| puts "The parameter is #{param}" }
eg.use_proc(99)
cs


실행결과

The parameter is 99


[특징]

1. eg.pass_in_block 메서드를 호출하면 매개변수 &action에 의해서 코드 블록이 넘겨졌는지 확인한다. 넘겨진 코드 블록을 @stored_proc 인스턴스 변수에 저장한다.


2. eg.use_proc 메서드를 매개변수 99와 함께 호출한다. @stored_proc.call(parameter)를 호출하여 1번에서 저장된 코드 블록을 실행한다.


proc 객체에 대해 call 메서드를 호출함으로써 원래의 블록을 호출한다는 점에 주의할 필요가 있다. 많은 루비 프로그래머들이 이러한 방식으로 블록을 변수에 저장하며 이후에 다시 호출한다. 이는 콜백이나 디스패치 테이블 등을 구현하는 훌륭한 방법이다. 여기서 좀 더 나아갈 수 있다. 메서드에서 매개변수 맨 앞에 앰퍼샌드를 붙여 블록을 객체로 변환할 수 있다면, 이 메서드에서 Proc 객체를 실행하고 그 결과를 다시 반환하면 어떻게 될까?


1
2
3
4
5
6
7
8
def create_block_object(&block)
    block
end
 
bo = create_block_object { |param| puts "You called me with #{param}" }
bo.call 99
bo.call "cat"
 
cs


[특징]

1. create_block_object를 호출하여 &block 매개변수에 의해 코드 블록이 객체로 변환되어 리턴된다.


2. 변수 bo에 객체화된 코드 블록이 저장된다.


3. bo.call 을 이용해서 코드블록을 실행한다. 


실행결과

You called me with 99

You called me with cat


이런 아이디어는 무척 유용하기에 루비에서는 블록을 객체로 변환하는 내장 메서드를 두 가지나 지원한다. lambda와 Proc.new가 바로 그것이다. 두 메서드는 블록을 받아서 Proc 객체를 반환한다.


1
2
3
4
bo = lambda { |param| puts "You called me with #{param}" }
bo.call 99
bo.call "cat"
 
cs


'Back-end > Ruby on Rails' 카테고리의 다른 글

[루비] 예외 처리  (0) 2019.02.13
[루비] 상속과 메시지  (0) 2019.02.11
[루비] 트랜잭션을 위한 블록  (0) 2019.02.10
[루비온레일즈] 웹 소켓  (0) 2019.02.06
[RSpec] 레일즈 테스트 코드 작성(작성중)  (0) 2019.01.24
댓글