Ruby code not executed after method call - ruby

Code is not executed (puts "hey") in the harvest method after the call to searchEmails(page). I'm probably missing something simple with Ruby because I'm just getting back into it.
def searchEmails(page_to_search)
begin
html = #agent.get(url).search('html').to_s
mail = html.scan(/['.'\w|-]*#+[a-z]+[.]+\w{2,}/).map.to_a
base = page_to_search.uri.to_s.split("//", 2).last.split("/", 2).first
mail.each{|e| #file.puts e+";"+base unless e.include? "example.com" or e.include? "email.com" or e.include? "domain.com" or e.include? "company.com" or e.length < 9 or e[0] == "#"}
end
end
def harvest(url)
begin
page = #agent.get(url)
searchEmails(page)
puts "hey"
rescue Exception
end
end
url="www.example.com"
harvest(url)

#agent.get(url) will fail with a bad url or network outage.
The problem in your code could be written as follows:
def do_something
begin
raise
puts "I will never get here!"
rescue
end
end
Since you can't get rid of the raise, you need to do something inside the rescue (most likely log it):
begin
#agent.get(url)
# ...
rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError,
Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError,
Net::ProtocolError => e
log(e.message, e.callback)
end

Related

ruby how to stop the execution after rescue

I have a func where when an exception was raised, I am rescuing it.
But the program continues to the next line and calls the next func create_request
But when there is exception, I do not want to continue
def validate_request_code options
if check_everything is good
#code to validate
else
errors << "something is gone bad"
end
[errors.size == 0, errors.size == 0 ? options : raise(ArgumentError, "Error while validating #{errors}")]
end
I am trying to catch/rescue the exception
def validate_request options
begin
validate_request_code options
rescue ArgumentError => e
log :error
rescue Exception => e
log :error
end
sleep 20
if options['action'] == "create"
create_request options
end
end
If by 'not continue' you mean that you want the original error to continue (i.e., you just want to take action on the way by), you can call raise inside the rescue block, which re-raises the original error.
def foo
begin
# stuff
rescue StandardError => e
# handle error
raise
end
end
You can also simply return from within the rescue block as well.
def foo
begin
# stuff
rescue StandardError => e
# handle error
return some_value
end
end
As an aside, generally you want to rescue StandardError rather than Exception. All the things that you can reasonably handle within your application are covered under the StandardError. The things outside that are things like out-of-memory, etc., that are outside your control.

My Rubocop doesn't like => e in Ruby error handling. Isn't => e standard?

Rubocop doesn't seem to like how I am handling my error. What should I do?
Lint/UselessAssignment: Useless assignment to variable - e.
rescue *exceptions_list => e
It is for the piece of code below:
def get_request(url_args = {})
http_connection(url_builder(url_args[:url], url_args[:page]))
rescue *exceptions_list => e
raise "#{e.message}"
end
The *exceptions_list that you see there is defined in a private method:
private
def exceptions_list
[
Net::HTTPBadResponse,
Net::HTTPHeaderSyntaxError,
Net::ProtocolError,
Errno::ECONNRESET,
Errno::EINVAL,
Timeout::Error,
EOFError,
SocketError
]
end
To avoid the rescue line being too long.
Question:
Having => e is pretty standard for error handling no? What should I do?
Thank you very much in advance! =)
Your example does not give Lint/UselessAssignment from rubocop, not at least with version 0.55.0
The UselessAssignment usually comes from something like this:
def do_things
..
rescue *exception_list => e # Useless assignment, e is never used in the block below.
puts "it failed :("
end
To fix this, you can remove the assignment if you're not using the raised exception for anything:
def do_things
..
rescue *exception_list
puts "it failed and i don't care why :D"
end

Skip to next host in array if an error is thrown

Say I have an array which is populated with IP addresses. Now say I have a method that tries to connect to each host in the array. In this particular instance I don't need to know any details about the failed connections, I just want to skip to the next host if one fails to connect or if ANY errors are thrown. How do I do this?
The problem I'm having is that, occasionally, when connecting to one of the hosts the program will throw an ENETUNREACH error and then kill the program. I tried solving it by just rescuing the error, but then what happens is the program will just stop executing without throwing any errors. How do I get it to skip the host in the array, and just move on to the next host?
def popen(host)
addr = Socket.getaddrinfo(host, nil)
sock = Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)
begin
sock.connect_nonblock(Socket.pack_sockaddr_in(22, addr[0][3]))
rescue Errno::EINPROGRESS
resp = IO.select(nil, [sock], nil, #timeout.to_i)
if resp.nil?
false
end
begin
if sock.connect_nonblock(Socket.pack_sockaddr_in(22, addr[0][3]))
sshlog(host, #user, #pass)
end
rescue Errno::ECONNREFUSED
false
end
end
sock
end
That is the connect method. And this:
def randIP
begin
threads = []
if #arg1 =~ /^([1-9][0-9]{0,2}|1000)$/
t1 = Time.now
s = 1
while s <= #arg1.to_i do
#host_arr << Array.new(4){rand(254)}.join('.')
s += 1
end
#host_arr.each do |ip|
threads << Thread.new do
begin
popen(ip)
rescue Errno::ENETUNREACH
end
end
end
threads.each do |thread|
thread.join
end
t2 = Time.now
time = t2 - t1
STDOUT.puts "done"
proxylst(#res_arr, #user, #pass)
else
puts "Host range too large! Must be a number between 1 and 1000."
end
rescue
false
end
end
Is a method that generates random IP addresses, puts them into an array, and uses the popen method above to attempt a connection on each host. Considering the nature of random IP address generation, chances are at least one out of 1000 hosts is going to be either invalid, or unreachable in some way. So what I need is a way to try every host in the array skipping any that throw errors.
typically how I handle this is like so:
exception_array = []
Connections.each do |con|
begin
#connection code
rescue Exception => e
exception_array << e
end
end
unless exception_array.empty?
msg = ""
exception_array.each do |e|
msg << e.to_s
end
raise msg
end
This way you keep track of all exceptions that were thrown without breaking the code on a failure.

I must be misunderstanding Celluloid

I currently have a script written in Ruby that scans a range of IP addresses and tries to connect to them. It's extremely slow at the moment. It takes up to 300 seconds to scan 254 hosts on the network, and that's obviously not very practical. What I'm trying to do is give the script some concurrency in hopes of speeding up the script. So far this is what I have:
require 'socket'
require 'celluloid'
$res_arr = []
class Ranger
include Celluloid
def initialize(host)
#host = host
#timeout = 1
end
def ip_range(host)
host =~ /(?:\d{1,3}\.){3}[xX*]{1,3}/
end
def ctrl(host)
begin
if ip_range(host)
strIP = host.gsub(/[xX*]/, '')
(1..254).each do |oct|
$res_arr << strIP+oct.to_s
end
else
puts "Invalid host!"
end
rescue
puts "onnection terminated."
end
end
def connect
addr = Socket.getaddrinfo(#host, nil)
sock = Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)
begin
sock.connect_nonblock(Socket.pack_sockaddr_in(22, addr[0][3]))
rescue Errno::EINPROGRESS
resp = IO.select(nil, [sock], nil, #timeout.to_i)
if resp.nil?
$res_arr << "#{#host} Firewalled!"
end
begin
if sock.connect_nonblock(Socket.pack_sockaddr_in(22, addr[0][3]))
$res_arr << "#{#host}Connected!"
end
rescue Errno::ECONNREFUSED
$res_arr << "#{#host} Refused!"
rescue
false
end
end
sock
end
def output(contents)
puts contents.value
end
end # Ranger
main = Ranger.new(ARGV[0])
main.ctrl(ARGV[0])
$res_arr.each do |ip|
scan = Ranger.new(ip)
scnftr = scan.future :connect
scan.output(scnftr)
end
The script works, but it takes just as long as before I included Celluloid at all. Am I misunderstanding how Celluloid works and what it's supposed to do?
Your problem is that each iteration of your loop starts a future, then immediately waits for it to return a value. What you want instead is start all futures, then wait for all futures to finish in two separate steps:
futures = $res_arr.map do |ip|
scan = Ranger.new(ip)
scan.future :connect
end
# now that all futures are running, we can start
# waiting for the first one to finish
futures.each do |future|
puts future.value
end
Here's another example from the celluloid source: https://github.com/celluloid/celluloid/blob/master/examples/simple_pmap.rb

How to catch all exceptions as soon as they occur by just one rescue statement

I know how to catch the exceptions but what we do is to put "rescue" after a suspicious section of a code. what if you had a lot functions sending a query to mysql through mysql2 gem and you want to catch their exceptions. One thing you can do is to put a "rescue" statement in each of them. but i want to do that just by one rescue statement. So I put a "rescue" in end of code and put all of code in a "begin" and "end" but it didn't work.
Here is my code and as you see there is a problem in mysql query and just because of "rescue" being end of file, it doesn't catch the exception but when I put it after that query it works.
require 'mysql2'
require 'colored'
begin
def log(string)
p "["+string.cyan+"]"
end
def err
p "["+"FAIL".red+"]"
end
def done
p "["+"DONE".red+"]"
end
class SqlClient
def initialize()
log "SqlClient/initialize"
puts "Host: \n"
#host = gets.strip
puts "User: \n"
#user = gets.strip
puts "Pass: \n"
#pass = gets.strip
#client = Mysql2::Client.new(host: #host , username: #user , password: #pass)
end
def list_databases()
puts "We are listing your databases(not just projects) \n \n \n "
#client.query("ELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA").each do |row|
p row["SCHEMA_NAME"]
end
puts "\n \n \n"
end
end
rescue Mysql2::Error
err
abort
end
`query': You have an error in your SQL syntax; check the manual that corresponds to your
MySQL server version for the right syntax to use near 'ELECT SCHEMA_NAME FROM
INFORMATION_SCHEMA.SCHEMATA' at line 1 (Mysql2::Error)
I'm not looking for something like:
begin
# my code
rescue # this line is right after the code which is going to have problem and we catch it.
end
I'm looking for something like this:
begin
# first method
# second method
# thrid method
# rest of code and etc ...
# now this is end of file:
rescue
end
but as you saw in my code, it didn't work.
UPDATE: I found a similar question here and it seems there will be no answer :| maybe this is a sort of ruby Weakness.
if you want to see ANY error just use e for example
begin
# your call to a method of Mysql2 gem. for example:
client = Mysql2::Client.new(:host => "localhost", :username => "root", etc...)
rescue => e
puts e.message
puts e.backtrace.inspect
end
In order to catch every exception you'd need to wrap each method call with a begin rescue end. When an exception is raised it bails out of the execution so it wouldn't hit the next methods.
To catch all errors I guess I'd do something like this. Keep in mind, this is ugly and I'd recommend for you NOT to do this, but... if you want to try, maybe try something like this:
all_errors = []
# first method you call
begin
# some error might happen here
first_response = Mysql2::Client.new(:host => "localhost", :username => "root", etc...)
rescue => e
all_errors << e
end
# second method you call
begin
# some error might happen here
second_response = Mysql2::Client.new(:host => "localhost", :username => "root", etc...)
rescue => e
all_errors << e
end
puts all_errors.inspect
After a quick search I've found: (http://coderrr.wordpress.com/2008/11/07/the-simple-way-to-print-exceptions-in-ruby/)
# catch all exceptions (anything that derives from Exception)
begin
...
rescue Exception
puts $!, $#
end
You could use an at_exit handler, which has access to the last exception in $!
like
at_exit {
puts "the exception that killed us is", $!
}
If you want to catch Exceptions "as soon as they occur" (not after they're caught) you could use ruby's "debug mode" (which outputs messages when they occur to the console) or ruby-debug see Is there any way to start the Ruby debugger on exception?
Just wrap all your code in:
begin
#yourcode
#as much as you want
rescue
end
Nobody seemed to notice it but using rescue without a class will catch all StandardError and there are so much more.
If you want to catch ALL exceptions you need to do
begin
# your code where you call SqlClient.new etc
rescue Exception => e
puts "error raised"
puts [e, e.backtrace].flatten.join("\n")
end
List of all error classes:
Exception
NoMemoryError
ScriptError
LoadError
NotImplementedError
SyntaxError
SignalException
Interrupt
StandardError
ArgumentError
IOError
EOFError
IndexError
LocalJumpError
NameError
NoMethodError
RangeError
FloatDomainError
RegexpError
RuntimeError
SecurityError
SystemCallError
SystemStackError
ThreadError
TypeError
ZeroDivisionError
SystemExit
fatal
have you tried adding an at_exit method in your class? This would allow you to do something when ruby is exiting. like in this article.
Ruby at_exit
or
From Ruby 2.0 API Docs
However beware of cleverly rescuing from an exception!
You'll start pulling your hair out down the road (or another dev will) when you try to figure out why your code isn't failing when it should be failing. I prefer to fail massively with a bright shiny sign saying the code failed here! hehe.
Good luck!

Resources