2016-07-08 15 views
1

Ich frage mich, warum die folgenden Tag-Methoden zu unterschiedlichen Ergebnissen führen:Ruby-Iterator Ausbeute

Methode 1:

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

Methode 2:

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

Wenn ich den folgenden Code lief in Terminal unter Verwendung der obigen Methoden:

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

Die erste gab mir:

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

Die zweite gab mir:

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

Die zweite ist die Ausgabe, die ich suche.

Wie kommt es, dass die erste Methode 'yield' ausgibt, bevor sie das Ergebnis in der Zeichenkette ausgibt?

Antwort

1

Nur um @ Tadmans Antwort Echo: Reihenfolge der Auswertung und Inkonsistenz der API. Ihr Block gibt manchmal Strings zurück und druckt manchmal Strings als Nebeneffekt.

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

Hier drucken Sie, dann ergeben. Wenn der Block eine Zeichenkette (einen der :li Blöcke) zurückgibt, wird er hier gedruckt. Wenn es ein :ul Block ist, dann seine Nebenwirkungen geschehen (Drucken von li Blöcken) und Null wird danach gedruckt.

Im anderen Fall

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

Ruby hat eine Saite zusammen drucken. Was bedeutet, vor jedem Druck nachzugeben. Was bedeutet, dass Nebenwirkungen auftreten vor Drucken der Eröffnung <ul>. Da der ul-Block null zurückgibt, wird er am Ende der Zeichenfolge leer gedruckt (<ul></ul>).

Macht es Sinn?

1

Das Hauptproblem ist die Reihenfolge der Operationen. Wenn Sie print anrufen, wird es sofort drucken, gibt es keine Verzögerung, die Probleme verursachen kann.

In Ruby ist es oft einfacher, mit Code zu arbeiten, der Zeichenfolgen zurückgibt als Code, der Nebenwirkungen wie Drucken verursacht. Wenn sie Zeichenfolgen zurückgeben, haben Sie die Kontrolle darüber, wohin diese Ausgabe geht. Wenn sie Dinge sofort drucken, müssen Sie sehr vorsichtig sein mit der Reihenfolge, in der Sie sie anrufen.

Die Art, wie Sie diesen Code in der Endmontage mit dem tag(:ul) Aufruf aufrufen, wird tatsächlich Ärger sein. Die zweite Version Ihrer Methode bestellt zufällig Dinge richtig.

Es ist nicht unbedingt einfach, dies zu beheben. Wenn Sie eine Zeichenfolge zurückgeben, wird nur die letzte Zeichenfolge aus Ihren drei tag-Aufrufen verwendet. Wenn Sie drucken, müssen Sie sicher sein, dass Sie die zweite Methode verwenden, damit es funktioniert. Innerhalb des Rails-Systems gibt es eine Möglichkeit, die Ausgabe dieser Dinge für Pufferzwecke zu erfassen, aber das ist eine sehr unordentliche Sache zu versuchen und zu tun, kann es wirklich verwirrt werden, wenn Sie versuchen und alle Fälle behandeln.

Wo möglich, erstellen Sie eine Art von Puffer diese Dinge können schreiben, dann, wenn alles fertig ist, schreibe das mit print oder was auch immer.

+0

Die erste Methode ist die falsche, BTW. –

+0

Ja, das wäre sinnvoller. Muss zu spät sein! – tadman