2016-07-08 3 views
1
Iは、次のタグ方法が異なる結果生じる理由を疑問に思ってい

ルビーイテレータ収率

方法1:

def tag(html) 
    print "<#{html}>#{yield}</#{html}>" 
end 

方法2:私は、次のコードを実行

def tag(html) 
    print "<#{html}>" 
    print yield 
    print "</#{html}>" 
end 

上記の方法を使用してください:

tag(:ul) do 
    tag(:li) { "It sparkles!" } 
    tag(:li) { "It shines!" } 
    tag(:li) { "It mesmerizes!" } 
end 

最初のものは私を与えた:

<li>It sparkles!</li><li>It shines!</li><li>It mesmerizes!</li><ul></ul> 

もう一つは私を与えた:

<ul><li>It sparkles!</li><li>It shines!</li><li>It mesmerizes!</li></ul> 

秒1は、私が探しています出力されます。

最初の方法は文字列に 'yield'の前に来るものを出力する前に 'yield'を出力しますか?

答えて

1

ちょうどエコー@タッドマンの答え:評価の順序とAPIの不一致。あなたのブロックは時には文字列を返し、時には文字列を副作用として出力します。

print "<#{html}>" 
    print yield 
    print "</#{html}>" 

ここで印刷してから出力します。ブロックが文字列(:liブロックのうちの1つ)を返した場合は、ここに表示されます。 :ulブロックの場合、の副作用(liブロックの印刷)が発生し、それ以降はnilが出力されます。

他の場合

print "<#{html}>#{yield}</#{html}>" 

Rubyは印刷する1つの文字列をアセンブルしなければなりません。これは、印刷前に降伏することを意味します。つまり、副作用はの前に発生します。の開始は<ul>です。 ulブロックがnilを返すので、それは文字列の最後に空白で表示されます(<ul></ul>)。

意味がありますか?

1

主な問題は操作の順序です。 printに電話すると、すぐにに印刷されますが、遅延はありません。問題が発生する可能性があります。

Rubyでは、印刷などの副作用を引き起こすコードではなく、文字列を返すコードを扱う方が簡単です。それらが文字列を返すと、その出力がどこに行くかを制御できます。彼らがすぐに物事を印刷する場合は、あなたがそれらを呼び出す順序に非常に注意する必要があります。tag(:ul)呼び出しで最終的なアセンブリでそのコードを呼び出す方法は実際には問題になるでしょう。あなたのメソッドの2番目のバージョンは同時に偶然に物事を正しく注文します。

これを修正することは必ずしも容易ではありません。文字列を返すと、3つのtag呼び出しの最後の文字列だけが使用されます。印刷する場合は、2番目の方法を使用して確実に機能させる必要があります。

Railsシステムでは、バッファリングの目的でこれらのものの出力をキャプチャする方法がありますが、これは非常に面倒なことですが、すべてのケースを処理して処理すると本当に混乱することがあります。

可能であれば、これらのものが書き込むことができる何らかの種類のバッファを作成し、すべてが完了したらprintなどで書き出します。

+0

最初の方法は間違ったものですが、btwです。 –

+0

ええ、それはもっと理にかなっています。あまりにも遅くなっているはずです! – tadman