2016-11-14 28 views
0

我經常發現自己處理這些類型的場景:你可以通過一個代碼塊,返回一個錯誤的方法?

require 'nokogiri' 
require "open-uri" 

url = "https://www.random_website.com/contains_info_I_want_to_parse" 
nokodoc = Nokogiri::HTML(open(url)) 
# Let's say one of the following line breaks the ruby script 
# because the element I'm searching doesn't contain an attribute. 
a = nokodoc.search('#element-1').attribute('href').text 
b = nokodoc.search('#element-2').attribute('href').text.gsub("a", "A") 
c = nokodoc.search('#element-3 h1').attribute('style').text.strip 

會發生什麼事,我會創造約30個變量都在尋找在一個頁面不同的元素,我會在循環代碼多個頁面。但是,這些頁面中的一些可能會有一個稍微不同的佈局,並且不會有這些div中的一個。這會破壞我的代碼(因爲你不能在nil上調用.attribute或.gsub)。但我永遠無法猜測到哪條線。 我去到的解決方案通常是圍繞每行:

begin 
    line #n 
rescue 
    puts "line #n caused an error" 
end 

我希望能夠做這樣的事情:

url = "https://www.random_website.com/contains_info_I_want_to_parse" 
nokodoc = Nokogiri::HTML(open(url)) 

catch_error(a, nokodoc.search('#element-1').attribute('href').text) 
catch_error(b, nokodoc.search('#element-2').attribute('href').text.gsub("a", "A")) 
catch_error(c, nokodoc.search('#element-3 h1').attribute('style').text.strip) 

def catch_error(variable_name, code) 
    begin 
    variable_name = code 
    rescue 
    puts "Code in #{variable_name} caused an error" 
    end 
    variable_name 
end 

我知道,把&每個新方法之前工作:

nokodoc.search('#element-1')&.attribute('href')&.text 

但是我希望能夠在終端上顯示'puts'的錯誤以查看我的代碼何時發生錯誤。

可能嗎?

回答

1

您不能將您的code作爲常規參數傳遞給方法,因爲在將其傳遞給catch_error方法之前,它將被評估(並引發異常)。你可以把它作爲一個塊 - 像

a = catch_error('element_1 href text') do 
    nokodoc.search('#element-1').attribute('href').text 
end 

def catch_error(error_description) 
    yield 
rescue 
    puts "#{error_description} caused an error" 
end 

請注意,您不能通過a的方法variable_name:尚未調用該方法之前的任何地方定義的,所以你會得到一個undefined local variable or method錯誤。即使您之前定義了a,也無法正常工作。如果您的代碼在不引發異常的情況下工作,該方法將返回正確的值,但該值不會存儲在方法範圍外的任何位置。如果發生異常,則variable_name將在方法(nil,如果您未定義它而定義它)之前具有任何值a,因此您的錯誤消息將輸出類似Code in caused an error的內容。這就是爲什麼我添加了error_description參數。

如果您不想每次都指定錯誤描述,那麼您也可以嘗試記錄消息和回溯。

a = catch_error(nokodoc) do |doc| 
    doc.search('#element-1').attribute('href').text 
end 

def catch_error(doc) 
    yield doc 
rescue => ex 
    puts doc.title # Or something else that identifies the document 
    puts ex.message 
    puts ex.backtrace.join("\n") 
end 

我在這裏做一個額外的變化:通過在文檔中的參數,以便rescue可以輕鬆登錄的東西,標識文檔,如果這一點很重要。

相關問題