2009-05-02 6 views
47

이 코드 조각을 Ruby on Rails 서적에서 보았습니다. 이 첫 번째보기에서 및 두 번째 도우미 모듈입니다. &blockattributes={} 것이 어떻게 작동하는지 이해할 수 없습니다. 누군가가 이것을 설명하는 어떤 종류의 자습서로 안내 할 수 있습니까? &blockRuby의 & block 무엇입니까? 그리고 어떻게이 방법으로 통과 할 수 있습니까?

<% hidden_div_if(@cart.items.empty?, :id => "cart") do %> 
<%= render(:partial => "cart", :object => @cart) %> 
<% end %> 

module StoreHelper 
def hidden_div_if(condition, attributes = {}, &block) 
    if condition 
    attributes["style"] = "display: none" 
    end 
    content_tag("div", attributes, &block) 
    end 
end 

답변

78

블록은 루비의 기본적인 부분입니다. 이 숫자는 do |arg0,arg1| ... end 또는 { |arg0,arg1,arg2| ... }으로 구분됩니다.

메소드에 전달할 콜백을 지정할 수 있습니다. 하나 &로 시작 최종 인수를 지정하여 을 캡처하여, 또는 하여 yield 키워드 사용 - 이 콜백은 두 가지 방법으로 호출 할 수 있습니다 : 우리의 콜백이 각각의 경우에 동일

irb> def meth_captures(arg, &block) 
     block.call(arg, 0) + block.call(arg.reverse , 1) 
    end 
#=> nil 
irb> meth_captures('pony') do |word, num| 
     puts "in callback! word = #{word.inspect}, num = #{num.inspect}" 
     word + num.to_s 
    end 
in callback! word = "pony" num = 0 
in callback! word = "ynop" num = 1 
#=> "pony0ynop1" 
irb> def meth_yields(arg) 
     yield(arg, 0) + yield(arg.upcase, 1) 
    end 
#=> nil 
irb> meth_yields('frog') do |word, num| 
     puts "in callback! word = #{word.inspect}, num = #{num.inspect}" 
     word + num.to_s 
    end 
in callback! word = "frog", num = 0 
in callback! word = "FROG", num = 1 
#=> "frog0FROG1" 

주 - 우리 개체에 콜백을 저장 한 다음 메서드로 전달하여 반복을 제거 할 수 있습니다. 이 작업은 lambda을 사용하여 객체의 콜백을 캡처하고 을 호출 한 다음 &이라는 접두어로 메소드에 전달할 수 있습니다.

irb> callback = lambda do |word, num| 
     puts "in callback! word = #{word.inspect}, num = #{num.inspect}" 
     word + num.to_s 
    end 
#=> #<Proc:[email protected](irb):22> 
irb> meth_captures('unicorn', &callback) 
in callback! word = "unicorn", num = 0 
in callback! word = "nrocinu", num = 1 
#=> "unicorn0nrocinu1" 
irb> meth_yields('plate', &callback) 
in callback! word = "plate", num = 0 
in callback! word = "PLATE", num = 1 
#=> "plate0PLATE1" 

그것은 여기 함수 함수 정의에

  • 의 마지막 인수에 접두어로 &의 다른 용도를 이해하는 것이 중요합니다, 그 객체로 어떤 전달 블록을 캡처
  • 에서 함수 호출, 주어진 콜백 객체를 블럭으로 확장한다.

주위를 둘러 보았을 때, 특히 그 곳곳에서 블럭이 사용된다. 반복기의 경우 Array#each과 같습니다.

+0

정말 고마워! – duykhoa

+0

고마워요. 아주 좋은 예입니다.하지만 Fixnum을 검사 할 때 요점은 무엇입니까? – sekmo

10

그 방법의 범위에 해당 코드 방법에 루비 코드의 일부를 전송하고 평가하는 방법이다. 위의 예제 코드에서는 부분적으로 이름이 지정된 cart가 div에 렌더링된다는 것을 의미합니다. 나는 컴퓨터 과학에서 이것을 위해 closure이라는 용어가 사용되었다고 생각한다.

그래서 당신의 예에서 &block은 다음과 같습니다

<%= render(:partial => "cart", :object => @cart) %> 

좋은 읽기와 블록, 발동과 lamdas의 설명은 Robert Sosinski's blog에서 찾을 수 있습니다.

+1

네는, 루비 블록은 단지 폐쇄 있습니다 : 그들은 다음과 같은 익숙한 구문을 가지고있다. 이에 대한 자세한 설명은 http://reprog.wordpress.com/2010/02/27/closures-finally-explained/을 참조하십시오. –

4

Re attributes = {} 이는 기본값을 갖는 메소드 인수 일뿐입니다. 따라서 hidden_div_if(whatever)을 호출하면 첫 번째 인수 만 전달하면 attributes은 기본적으로 빈 해시가됩니다.

을 먼저 해시로 초기화 할 필요가 없으므로 나중에 attributes["style"]으로 설정하는 것이 간단하므로 유용합니다. (어떤 그럼에도 불구하고 (attributes ||= {})["style"] = …로 간단하게 할 수 있습니다.)


&block은 약간 더 복잡하다.

Ruby 메서드는 특수 구문 method(args) { |block_args| block_code }을 사용하여 블록 인 마지막 인수를 사용할 수 있습니다. &block은 기본적으로 block 변수에 해당 블록을 Proc 개체로 캡처합니다. 따라서 block은 익명 프로 시저를 가리키는 변수 일뿐입니다. 호출이 실제로 content_tag(…) { block originally passed to hidden_if_div }


그래서 어쩌면 내가 정말 여기에 혼란 경우처럼

나중에 content_tag가 호출

&block가 마지막 인수로 전달됩니다, 그것은 블록으로 확장합니다. 당신이 해야하는 google은 "ruby default arguments"와 "ruby blocks"입니다.

1

그것은 다음과 같이 작동

@cart.items.empty?

:id => "cart" 그것이 마지막 경우 당신이 PARAM 해시에 {} 제거 할 수있는 규칙에 따라 속성이되는 codition에게 있습니다. 이 div 태그를 생성합니다 : "없음 표시"그럼

카트가이 값으로 속성 스타일을 추가 할 것입니다 비어있는 경우

블록은 함수 내 너무

render(:partial => "cart", :object => @cart)

입니다 @cart의 내용으로 부분보기 카트를 렌더링 한 결과 블록을 실행 한 결과의 내용으로 채워집니다.

3

Ruby는 컴퓨터 과학 커뮤니티에서 클로저라고하는 블록, Procs 및 lambdas를 구현합니다. Ruby를 배우기 시작하면 다음과 같은 코드가 실행됩니다.

a = ["dog", "cat", "bird"] 
a.alter_each! do |n, i| 
    "#{i}_#{n}" 
end 

그럼 어떻게 될까요?

동물 이름 배열로 시작하여 alter_each! 메서드는 블록을 전달합니다. 이 코드 블록에서 각 항목을 변경하는 방법을 지정할 수 있습니다. 이 예제에서는 각 동물 이름 앞에 배열의 위치를 ​​붙입니다. alter_each! 메서드는 값과 인덱스를 전달하는 블록을 실행할 각 항목을 반복합니다. 우리의 블록은이 매개 변수를 캡처하고 인덱스에 접두사를 붙여 이름을 반환합니다. 이제 alter_each! 방법.

블록을 자동으로 yield 키워드에 할당하기 때문에이 메서드는 매개 변수를 지정하지 않습니다. yield는 배열의 각 항목의 값과 인덱스를 전달하고 원래 값을 덮어 쓰는 함수처럼 호출됩니다.

class Array 
    def alter_each! 
    self.each_with_index do |n, i| 
     self[i] = yield(n,i) 
    end 
    end 
end 

이 메서드에 param을 전달해야하는 경우 어떻게해야합니까?

매개 변수를 허용하고 마지막으로 앰퍼샌드로 시작하는 매개 변수로 블록을 catch하도록 메서드 서명을 수정할 수 있습니다. 아래 예제에서 블록은 & 블록 매개 변수로 캡처됩니다.이 param은 호출 메소드를 호출합니다.이는 수율

class Array 
    def modify_each!(add_one = true, &block) 
    self.each_with_index do |n, i| 
     j = (add_one) ? (i + 1) : i 
     self[i] = block.call(n,j) 
    end 
    end 
end 
를 사용하는 장소에

Full article on ruby blocks

18

(컴퓨터 과학의 폐쇄로 함) 블록, 프로세서 수와 람다 루비의 가장 강력한 측면 중 하나, 또한 가장 오해 중 하나입니다 . 이것은 루비가 다소 독특한 방식으로 클로저를 처리하기 때문일 것입니다. 일을 더 복잡하게 만드는 것은 루비가 네 가지 클로저 사용 방법을 가지고 있다는 것입니다. 각각의 클로저는 조금씩 다르며 때로는 무의미합니다. Ruby에서 클로저가 어떻게 작동하는지에 대한 아주 좋은 정보가있는 사이트가 꽤 많이 있습니다. 그러나 나는 아직 거기에 좋은, 확실한 가이드를 찾을 수 있습니다.

class Array 
    def iterate!(&code) 
    self.each_with_index do |n, i| 
     self[i] = code.call(n) 
    end 
    end 
end 

array = [1, 2, 3, 4] 

array.iterate! do |n| 
    n ** 2 
end 

절차, AKA, 프로세서 수

블록 그러나 우리는 우리의 처분에 여러 블록이 그들에게 여러 번 사용할 수 있습니다, 매우 편리하고 구문 간단합니다. 따라서 같은 블록을 반복적으로 통과 시키려면 우리가 스스로를 반복해야합니다. 그러나 Ruby는 완전히 객체 지향적이므로 재사용 가능한 코드를 객체 자체로 저장하여 매우 명확하게 처리 할 수 ​​있습니다. 이 재사용 가능한 코드를 Proc (프로 시저의 약자)라고합니다. 블록과 Procs의 유일한 차이점은 블록이 저장 될 수없는 Proc이기 때문에 한 번 사용하는 솔루션이라는 것입니다. 프로세서 수와의 협력을 통해, 우리는 다음과 같은 일을 시작할 수 있습니다

class Array 
    def iterate!(code) 
    self.each_with_index do |n, i| 
     self[i] = code.call(n) 
    end 
    end 
end 

array_1 = [1, 2, 3, 4] 
array_2 = [2, 3, 4, 5] 

square = Proc.new do |n| 
    n ** 2 
end 

주면서

지금까지 당신이 사용한 프로세서 수를 두 가지 방법으로, 속성으로 직접 전달하고 변수로 저장. 이러한 Procs는 다른 언어가 익명 함수 또는 람다라고 부르는 것과 매우 유사하게 작동합니다. 더 재미있는 것들을 만들기 위해서, 람다도 루비 내에서 사용할 수 있습니다. 보세요 :

class Array 
    def iterate!(code) 
    self.each_with_index do |n, i| 
     self[i] = code.call(n) 
    end 
    end 
end 

array = [1, 2, 3, 4] 

array.iterate!(lambda { |n| n ** 2 }) 

puts array.inspect 

블록

가장 많이, 가장 쉽고 틀림없이 "루비처럼"루비에서 클로저를 사용하는 방법은 블록입니다.

array = [1, 2, 3, 4] 

array.collect! do |n| 
    n ** 2 
end 

puts array.inspect 

# => [1, 4, 9, 16] 
+0

나는 비슷한 예제를 보았습니다. http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/ 그러나'| n으로 전달되는 것에 관해서는 혼란 스럽습니다. i |'는 배열 내의 값과 인덱스 위치입니까? – Tom

+0

OK each_with_index가 바보 같았습니다 :'each_with_index | item, index |'그래서 나는 정말로 질문 할 필요가 없었습니다. – Tom

+1

robersosinki의 사이트에서이 대답을 복사 할 때 두 배열에 'square'Proc를 전달하는 줄을 포함하는 것을 잊었습니다. 원래 버전을 읽을 때까지 약간 혼란 스러웠습니다. 다음 번에 당신의 소스를 지적 해주십시오. – moosefetcher

관련 문제