2016-03-30 6 views
-2

Ich könnte das offensichtliche hier fehlen, aber dieser Code schlägt fehl, wenn ich die return -Klausel verwenden, wenn es rekursiv auf Net::HTTPRedirection Fall aufrufen.Ruby rekursive Methode benötigt Return-Klausel

def fetch_headers(limit = REDIRECT_LIMIT) 
    # You should choose a better exception. 
    raise ArgumentError, 'too many HTTP redirects' if limit == 0 
    http = Net::HTTP.new(@uri.host, @uri.port) 
    http.use_ssl = true if @uri.scheme == 'https' 
    request_uri = @uri.request_uri.nil? ? '/' : @uri.request_uri 
    http.request_head(request_uri) do |response| 
     case response 
     when Net::HTTPSuccess then 
     return response 
     when Net::HTTPRedirection then 
     location = response['location'] 
     parsed_location = URI.parse location 
     @uri = parsed_location.absolute? ? parsed_location : @uri.merge(parsed_location) 
     fetch_headers(limit - 1) 
     else 
     return response.value 
     end 
    end 
    end 

Der Anrufer Methode:

def perform(link_id) 
    link = Link.find(link_id) 
    url = link.url =~ /^http/ ? link.url : "http://#{link.url}" 
    @uri = URI.parse url 
    headers = fetch_headers 
    case headers.content_type 
    when /application/ 
     filename = File.basename(@uri.path) 
     link.update title: filename 
    when /html/ 
     response = fetch_page 
     page = Nokogiri::HTML(response) 
     link.update title: page_title(page), description: page_description(page) 
    else 
     logger.warn "URL #{url} with unknow mime-type: #{headers.content_type}" 
    end 
    end 

Hier ist die Spezifikation bei mir läuft:

it 'follows the redirects using relative URL' do 
    link = create(:link, url: url) 
    path = '/welcome.html' 
    stub_request(:head, url).to_return(status: 302, body: '', 
            headers: { 'Location' => path }) 
    redirect_url = "#{url}#{path}" 
    stub_request(:head, redirect_url).to_return(status: 200, body: '', 
               headers: html_header) 
    stub_request(:get, redirect_url).to_return(status: 200, body: title_html_raw, 
              headers: html_header) 

    UrlScrapperJob.perform_now link.id 
    link.reload 
    expect(link.title).to match(/page title/) 
end 

Hier sind das Ergebnis fetch_headers Methode:

Mit der Rückkehr-Klausel: #<Net::HTTPOK 200 readbody=true>

Ohne die Rückkehr Klausel: #<Net::HTTPFound 302 readbody=true>

Das Ergebnis, das ich die HTTPOK 200 wäre zu erwarten, weil es die Umleitungen, bis eine 200 OK folgen sollte.

+0

Können Sie etwas hinzufügen, was Sie mit "failing" meinen? – Linuxios

+0

@Linuxios Ich habe das Ergebnis aktualisiert und den Mittelwert des Scheiterns erklärt. –

Antwort

2

Die Differenz ist der Wert, zurückgegeben von fetch_headers Funktion.

return gibt das Argument als Ergebnis eines Funktionsaufrufs zurück.

Ohne explizite return ist der Rückgabewert, was http.request_head(request_uri, &block) zurückgibt, was anscheinend die unendliche Rekursion verursacht.

Sie könnten

http.request_head(request_uri) do |response| 
    case response 
    when Net::HTTPSuccess then 
    response 
    when Net::HTTPRedirection then 
    location = response['location'] 
    parsed_location = URI.parse location 
    @uri = parsed_location.absolute? ? parsed_location : @uri.merge(parsed_location) 
    fetch_headers(limit - 1) 
    else 
    response.value 
    end 
end.tap { |result| puts result } # ⇐ here 

zu untersuchen, um versuchen wollen, was ohne explizite return tatsächliches Ergebnis.

+0

Bitte überprüfen Sie mein Update, um das Ergebnis in beiden Fällen zu sehen. –

+0

Die Sache, die Sie hier vermissen, ist wahrscheinlich, dass 'return' ** von allen Codeblocks zur obersten Ebene ** zurückkehrt. Der Kontrollfluss im Fall von 302 ist: "Holen "⇒'Fetch'⇒ [innerhalb von 2 Blöcken] ⇒" 200 "⇒ [innerhalb von 1] ⇒ "302" aufgrund von Rekursion. Der normale Kontrollfluss zwingt das erste Ergebnis (302), das als Funktionsergebnis zurückgegeben wird. OTOH, 'return' gibt das Ergebnis an die oberste Ebene zurück. – mudasobwa