ignoring errors and proceeding in ruby - ruby

whenever there is an exception call that is raised, the script terminates.
do i have to resort to putting each action ? it gets very complicated fast.....
begin
#someaction
begin
#someaction2
rescue
end
rescue
end

You could use some sort of AOP mechanism to surround every method call with exception handling code (like Aquarium: http://aquarium.rubyforge.org/), or put rescue nil after every line of code, but I'm guessing that if you need to do that, then the exceptions raised are not really signalling exceptional situations in your app (which is bad) or you want to try to continue even in a situation where there's really no point to do so (which is even worse). Anyway I'd advise you to reconsider what you really need to do, because it seems to me that you are approaching the problem in a wrong way.

It's difficult to give a specific answer because I don't know what your program does.
But in general terms, I find that the best way to deal with this is to put the code that could fail into one or more seperate methods (and perhaps the method name should reflect this).
This has a number of advantages. First of all, it means that the rest of your code doesn't have to be hedged around with exception handling; secondly, if the "dangerous" actions are carefully split up into logical groups, you may be able to do exception handling on the method, not the actual actions. Stupid example:
my_list = get_list("one") # perfectly safe method
my_list.each do |x|
begin
x.dangerous_file_method() # dangerous method
rescue
x.status = 1
end
end

Related

Can you yield inside a code block in Ruby?

I'm currently learning Ruby and doing so by reading the popular book "The well-grounded Rubyist". I do understand code blocks pretty decently, or so I thought, until I hit this code example from the book on page 191:
open_user_file do |filename|
fh = File.open(filename)
yield fh
fh.close
rescue
puts "Couldn't open your file"
end
Now the thing I do no quite get here is, whom do I yield to when yielding within a code block? The way I understood it is that if you call a method that can yield and you provided a code block, the method will yield to your code block (maybe even with arguments), your code block executes and then gives control back to the method. But here in this code example we do not yield within the method, but in the code block. Could someone explain to me how this works and how a construct like this may look like? Any clarifications are appreciated!
(P.S. please don't tell me "You shouldn't do this". I am not asking because I want to do this in production code, I merely want to understand the inner workings of Ruby in-depth.)
The code you have there does in fact not work, because there is no block to yield to.
You will get a LocalJumpError, which gets swallowed by the catch-all rescue, and thus it will look like there is a problem with the file, when in fact, there is actually a programming error. (Teachable moment: never ever do a blanket catch-all rescue, always rescue only exactly those exceptions you want to handle.)

Rescuing and catching at the same time

If I wanted to both rescue a potential error and catch a potential throw, how should I nest them? Are the two below equivalent, and it is just a matter of preference?
begin
catch(:some_throw) do
...
end
rescue SomeError
...
end
catch(:some_throw) do
begin
...
rescue SomeError
...
end
end
Its an opinion-based question, and one can argue either way. So, in my opinion...
If you are planning to return a value via throw, then, second option seems useful as it will let you rescue an error and throw some kind of default value.
Even if you were using throw and catch just to manage loop iterations and breaking out of it on certain conditions, second option still seems more readable and encapsulates all the logic inside the catch block.
They are not entirely equivalent. With the first alternative, the catch will only intercept values being thrown in the begin clause, while the second includes ones from rescue too.
That being said, if you are in the case, when the two are equivalent (aka you don't throw :some_throw in the rescue clause):
The argument for the first alternative would be that we tend to think that begin - rescue blocks enclose "regular" statements. throw - catch being rarely used and having a non-error semantic are more "regular"-y.
The argument for the second alternative would be that one should strive to enclose the least amount (only the possibly failing) of code in begin - rescue clauses.
Personally, I like the first one better.

ruby - how can i still do something when there's error (example: NameError)

i manage to do "something"(like deleting files,etc) when exit or exit! is called from Object.
by changing the method exit and exit! inside Object class. (at_exit is too unreliable)
but then the "something" never execute if there's error such as NameError, etc.
is there way so i can make "something" that still execute if there's error.
(any error possible if necessary).
something like at_exit but works with all errors
thanks in advance for assistance. and forgive me if there's already question ask for this.
i do search a lot before asking here. and found nothing.
edit: i don't know where the original author of the code place the method. since the original author load it from dll files in the exe program the author used for launcher. (i can only edit After the original code take place...). so i think i need another approach for this... but i manage to make a workaround for my problem... by putting begin rescue in other places that send data to the original object. i filter the data send and throw my own error before it reach the main program... so i guess this works too.
Borrowing from an answer on a different thread, and definitely along the lines of what Marek commented, this is how you should handle errors in Ruby:
begin
# something which might raise an exception
rescue SomeExceptionClass => some_variable
# code that deals with some exception
rescue SomeOtherException => some_other_variable
# code that deals with some other exception
else
# code that runs only if *no* exception was raised
ensure
# ensure that this code always runs, no matter what
end
Original credit: Begin, Rescue and Ensure in Ruby?

Why are else statements discouraged in Ruby?

I was looking for a Ruby code quality tool the other day, and I came across the pelusa gem, which looks interesting. One of the things it checks for is the number of else statements used in a given Ruby file.
My question is, why are these bad? I understand that if/else statements often add a great deal of complexity (and I get that the goal is to reduce code complexity) but how can a method that checks two cases be written without an else?
To recap, I have two questions:
1) Is there a reason other than reducing code complexity that else statements could be avoided?
2) Here's a sample method from the app I'm working on that uses an else statement. How would you write this without one? The only option I could think of would be a ternary statement, but there's enough logic in here that I think a ternary statement would actually be more complex and harder to read.
def deliver_email_verification_instructions
if Rails.env.test? || Rails.env.development?
deliver_email_verification_instructions!
else
delay.deliver_email_verification_instructions!
end
end
If you wrote this with a ternary operator, it would be:
def deliver_email_verification_instructions
(Rails.env.test? || Rails.env.development?) ? deliver_email_verification_instructions! : delay.deliver_email_verification_instructions!
end
Is that right? If so, isn't that way harder to read? Doesn't an else statement help break this up? Is there another, better, else-less way to write this that I'm not thinking of?
I guess I'm looking for stylistic considerations here.
Let me begin by saying that there isn't really anything wrong with your code, and generally you should be aware that whatever a code quality tool tells you might be complete nonsense, because it lacks the context to evaluate what you are actually doing.
But back to the code. If there was a class that had exactly one method where the snippet
if Rails.env.test? || Rails.env.development?
# Do stuff
else
# Do other stuff
end
occurred, that would be completely fine (there are always different approaches to a given thing, but you need not worry about that, even if programmers will hate you for not arguing with them about it :D).
Now comes the tricky part. People are lazy as hell, and thusly code snippets like the one above are easy targets for copy/paste coding (this is why people will argue that one should avoid them in the first place, because if you expand a class later you are more likely to just copy and paste stuff than to actually refactor it).
Let's look at your code snippet as an example. I'm basically proposing the same thing as #Mik_Die, however his example is equally prone to be copy/pasted as yours. Therefore, would should be done (IMO) is this:
class Foo
def initialize
#target = (Rails.env.test? || Rails.env.development?) ? self : delay
end
def deliver_email_verification_instructions
#target.deliver_email_verification_instructions!
end
end
This might not be applicable to your app as is, but I hope you get the idea, which is: Don't repeat yourself. Ever. Every time you repeat yourself, not only are you making your code less maintainable, but as a result also more prone to errors in the future, because one or even 99/100 occurrences of whatever you've copied and pasted might be changed, but the one remaining occurrence is what causes the #disasterOfEpicProportions in the end :)
Another point that I've forgotten was brought up by #RayToal (thanks :), which is that if/else constructs are often used in combination with boolean input parameters, resulting in constructs such as this one (actual code from a project I have to maintain):
class String
def uc(only_first=false)
if only_first
capitalize
else
upcase
end
end
end
Let us ignore the obvious method naming and monkey patching issues here, and focus on the if/else construct, which is used to give the uc method two different behaviors depending on the parameter only_first. Such code is a violation of the Single Responsibility Principle, because your method is doing more than one thing, which is why you should've written two methods in the first place.
def deliver_email_verification_instructions
subj = (Rails.env.test? || Rails.env.development?) ? self : delay
subj.deliver_email_verification_instructions!
end

Should the return value of "save" always be checked when using ActiveRecord?

In general, should the return value of save always be checked when using ActiveRecord?
For example, I've come across some code like this:
def foo(active_record_instance)
active_record_instance.field_1 = 'a'
active_record_instance.field_2 = 'b'
# ...15 more lines...
active_record_instance.save # <==
baz = bar(active_record_instance.id)
# ...15 more lines that use baz...
baz
end
def bar(id)
instance = ActiveRecordSubclass.find(id)
instance.field_3 = instance.field_1 + instance.field_2
instance
end
That's slightly contrived, but it's a fairly realistic example for the codebase I'm working on. (This isn't an isolated case of this pattern.)
Given that the validation for ActiveRecordSubclass is in flux and change is possible in the near future (or even a year from now), my thought is that the return value of active_record_instance.save should be checked. Another alternative would be to use active_record_instance.save!.
Is it appropriate to check whether or not the record saved? Or is the foo method micromanaging something that should not be its concern, given that the current validation does not fail?
Maybe you could use save! method, catch exception and put your logic inside .
begin
foo.save!
rescue ActiveRecord::RecordInvalid
# handle logic here
end
The real answer is, `do you care about the data in question?`
If you care about the data, then yes, you should return something false or throw an exception, and somehow communicate why it failed validation.
If you really don't care if it saves, and it will be tried in 10 seconds, at which point you expect it to work, then ignore the error.
As a personal preference and experience, I would rather have something fail fast and dramatically, than spend hours or days hunting down a bug because something 50 steps before didn't actually save.

Resources