=> Operator in Ruby - ruby

I have been searching thoroughly on Google but I can't seem to be able to find the answer. I am wondering what the => operator means in the Ruby code shown below:
def test_raising_a_particular_error
result = nil
begin
# 'raise' and 'fail' are synonyms
raise MySpecialError, "My Message"
rescue MySpecialError => ex
result = :exception_handled
end
assert_equal :exception_handled, result
assert_equal "My Message", ex.message
end

There is no => operator in Ruby. There are, however, two uses of => in Ruby:
in a Hash literal between the key object and the value object
in a rescue clause after the exception filter expression, naming the variable the exception should be bound to
So, in this case, it's #2, and means "rescue any exception that is an instance of MySpecialError and bind it to the local variable named ex".

Related

What are the empty single quotes for after rescue?

while t = Integer(gets.chomp) rescue ''
if t.is_a? Integer
break
else
print "Please enter a whole number "
end
end
I'm just trying to figure out exactly why I need those empty single quotes after rescue for this loop to work.
because Integer(gets.chomp) can raise an exception, which caught by rescue and assign to t value as empty string
This is referred to as an inline rescue. If t = Integer(gets.chomp) raises any exception inheriting from StandardError it will be rescued and an empty string will be returned instead. You can think of it like this:
begin
do_something
rescue
''
end
The problem with this approach is that you can't specify exception classes to rescue from, so you may accidentally mask errors that you didn't expect, like a NoMethodError raised when misspelling the chomp method:
Integer(gets.chmp) rescue ''
#=> ""

Ruby Syntax of '=>' (hashrocket)

I tried this earlier and everyone got off on rescue block syntax. Please don't go there. Given the following working code:
begin
(1..1000).each do |i|
puts i
sleep 1
end
rescue Exception => e
puts "\nCaught exception..."
puts "Exception class: #{e.class}"
end
Pressing CTRL+C while it is running prints out "Caught exception...", as expected. What exactly is going on syntax wise in the rescue line, particularly between Exception and the variable e with the => in between?
The word "rescue" is a keyword... part of the ruby language. "e" is a variable, and could just as functionally be "a", "b", or "c". The following code works just as well.
begin
(1..1000).each do |i|
puts i
sleep 1
end
rescue Exception => b
puts "\nCaught exception..."
puts "Exception class: #{b.class}"
end
What are "Exception" and "=>"? Is there another way to write this expression to make it more intelligible from a syntactical point of view? I don't think we're dealing with a hash here because the following code compiles but throws an error as soon as CTRL+C is pressed (undefined local variable or method `e').
begin
(1..1000).each do |i|
puts i
sleep 1
end
rescue { Exception => b }
puts "\nCaught exception..."
puts "Exception class: #{b.class}"
end
Can someone explain what is going on? and specifically what language element '=>' (hashrocket) is in this specific example since it seems to have nothing to do with hashes?
I'm sorry to inform you that this is just one-off syntax that doesn't really have any relation to other Ruby syntax.
Given the expression:
begin
# ...
rescue FooError, BarError => ex
# ...
end
FooError, BarError is the list of exception classes (usually subclasses of StandardError) that will be rescued. This behaves just like an argument list, so you can (if you want) do stuff like this:
my_exception_classes = [ FooError, BarError ]
begin
# ...
rescue *my_exception_classes => ex
# ...
end
It's worth noting that you shouldn't, generally, use Exception here because it will rescue all exceptions, including things like SignalException::Interrupt and NoMemoryError, which usually isn't what you want.
=> is just syntax, and arguably not the best choice of syntax for the reason that it leads to questions like your own.
ex is the name of a local variable into which the exception object will be put.
Digging deeper
If you're into reading parser grammars, it's always fun looking at Ruby's YACC grammar in parse.y. It's not especially easy to read, but we can see the grammar for a rescue expression, called opt_rescue in the grammar, here:
opt_rescue : k_rescue exc_list exc_var then
compstmt
opt_rescue
k_rescue is of course the keyword rescue. exc_list is the list of exception classes which, like I said, is just like an argument list:
exc_list : arg_value
exc_var is the part where the variable to put the exception in is designated:
exc_var : tASSOC lhs
And here, tASSOC is of course our friend the hashrocket (=>), and lhs, i.e. “left-hand side,” is an expression you'd find to the left of an assignment expression (like, say, the name of a variable).
compstmt is basically “any valid Ruby code,” and then there’s opt_rescue again, since you can (optionally) have many rescues in a begin or def block.
As you can see, the only thing this syntax has in common with a Hash is tASSOC.

Does it matter which way a string method is used?

Codeacademy teaches that you can chain multiple methods together as such:
user_input.method1.method2.method3
However, in a later lesson they display some methods like this:
user_input = gets.chomp
user_input.downcase!
I combined them:
user_input = gets.chomp.downcase!
When I use it this way:
user_input = gets.chomp.downcase!
if user_input.include? "s"
...
I receive an error "undefined method `include?'". If I change it to the following, it works fine:
user_input = gets.chomp
user_input.downcase!
if user_input.include? "s"
...
I'm at a loss. I'm concerned whether or not this is a quirk with their console or if this is just how I should be doing it in Ruby. If someone could tell me which way is right, I'd appreciate it. If both are right, that's OK too.
Firstly, in case you do not yet fully understand, assignment of values to variables are done through =, and that you could inspect what variable type it is by appending .class to anything.
Consider the following:
name = 'John'
puts name
# => John
puts name.class
# => String
Now, secondly, it should be noted that the return values of ALL methods are ALL different. But all of them can be identified into two types:
Methods that:
return self
return anything other than self
Example for 1.
-- methods that return self, which you could say methods that return the same type of object which in our specific case, a String
name = 'John'
puts name
# => 'John'
puts name.class
# => String
downcased_name = name.downcase
puts downcased_name
# => john
puts downcased_name.class
# => String
deleted_downcased_name = downcased_name.delete('h')
puts deleted_downcased_name
# => jon
puts deleted_downcased_name.class
# => String
# All of the above can be just simplified into:
deleted_downcased_name2 = 'John'.downcase.delete('h')
puts deleted_downcased_name2
# => jon
puts deleted_downcased_name2.class
# => String
Notice that deleted_downcased_name and deleted_downcased_name2 are the same, because you could treat the chained methods as if you are chaining the return values which is 'John' -> 'john' -> 'jon'.
Example for 2
-- methods that return anything but self, which you could say methods that return a different type.
In our specific case, String's downcase! returns either a String or NilClass (reference here)
returning String if the string changes, or
returning nil if string is already downcased to begin with (no change).
or another String's method: start_with? (reference here)
returning true or false
This is where chaining of methods will not work (raises an error), when you try to use a String method as a chain to nil value.
Consider the following
name = 'mary'
puts name
# => 'mary'
puts name.class
# => String
downcased_name = name.downcase!
puts downcased_name
# => nil
puts downcased_name.class
# => NilClass
downcased_name.delete('h')
# => This will raise the following error
# NoMethodError: undefined method `delete' for nil:NilClass
The error above is because downcased_name is a type of NilClass where you are expecting it to be a type of String. Therefore you cannot chain any string method on it anymore. You can only chain String methods on a String type of value. Similarly, you can only chain Number methods on a Number type of value.
Whenever in doubt, you could always check the documentation to check what a method does, and what its return value and type.
The problem you are encountering is with the bang method downcase!.
This is basically saying "mutate the original string so that it is downcase".
The important part is that this returns nil. As such you are actually calling include? on nil.
If you use the non bang method downcase instead, it is saying "downcase the previously chained thing but do not mutate the original". The key difference is that it returns the result rather than nil.
Here is an example:
str = "ABCD"
str.downcase!
=> nil
str
=> "abcd"
str = "ABCD"
str.downcase
=> "abcd"
str
=> "ABCD" # Note str is still unchanged unless you set str = str.downcase
Welcome to Ruby! While your apprenticeship at Codeacademy may be limited, you'll continue to refer to language API documentation throughout your career. API documentation is a description of what the language (or a library) does for you. In this case, you're using downcase! which, as one commenter points out, does not always return a String. When it takes no action, it returns nil. Nil is an Object in Ruby (like everything else), but the 'include?' method isn't defined for nil, which explains your error. (It's one of the most common errors in Ruby, learn its meaning.)
So, in fact, what's breaking here isn't your method chain. It's that one of the intermediate methods isn't returning a value of the type you expect (nil instead of some kind of String).
Chaining non destructive methods like:
string.chomp.downcase...
has the advantage that the code is concise, but is not efficient if you are not interested in the original state of the object, and just want the final result because it creates intermediate objects during the chain.
On the other hand, applying destructive methods sequentially to the same object:
string.chomp!
string.downcase!
...
is more efficient if you do not need to keep the original state of the object, but is not concise.
Combining methods that may return an object of a different class (particularly nil) as:
string = gets.chomp!.downcase!...
is wrong because the result can become nil at some point in the chain.
Applying a potentially nil-returning method at only the last position as you did:
string = gets.chomp.downcase!
is still not useful if you expect string to always be a string, and can easily lead to an error as you did.
If you want to chain these methods in you example, perhaps you can do this:
user_input = gets.tap(&:chomp!).tap(&:downcase!)
if user_input.include?("s")
...

Understanding syntax of the statement "rescue ErrorType1, ErrorType2 => ex"

A quick query:
How would a Java programmer will understand the following Ruby statement:
rescue ErrorType1, ErrorType2 => ex
That is, I want to put brackets/parenthesis around it explicitly.
So, is it?
rescue(ErrorType1, {ErrorType2 => ex})
or,
rescue({[ErrorType1, ErrorType2] => ex})
or, something else...
About the syntax:
rescue ErrorType1, ErrorType2 => ex
Please note following:
There is no hash involved
'rescue' is not a method, you can't even write it as rescue(ErrorType1, ErrorType2 => ex)
Ruby places a reference to raised associated exception into the
global variable $!.
In the above form, the 'rescue' takes a special argument where
you give the name of a local variable to receive the matched
exception, which is more readable then using $!.
Now, look at the syntax again...
rescue is a control structure with it's own syntax, it's not a method call, so your 2nd and 3rd code blocks are invalid syntax, you aren't not passing any arguments.
rescue <exception-class1>[, <exception-class2>] => <a variable to assign the exception to>
so when doing rescue TypeError, StandardError => my_exception it will catch any TypeError or StandardError exception that is raised and assign it to the my_exception local variable.
I suggest the recently translated Ruby Hacking Guide (search for "rescue").
Look at the below code :
begin
a=1/0
rescue => e
p e.class
p defined?(e)
end
# >> ZeroDivisionError
# >> "local-variable"
Where e is a local variable to that exception handling block. In Ruby local variables are created using assignment operation,but in case of exception handling,reference to the currently raised exception is assigned to the local variable e using the hash rocket(=>),instead of =. This is as per design. Don't think of that it is a Hash.
In Ruby we use one or more rescue clauses to tell Ruby the types of exceptions we want to handle.If you write a rescue clause with no parameter list, the parameter defaults to StandardError. Each rescue clause can specify multiple exceptions to catch. At the end of each rescue clause you can give Ruby the name of a local variable to receive the matched exception. The parameters to the rescue clause can also be arbitrary expressions (including method calls) that return an Exception class. If we use raise with no parameters, it re-raises the exception.Handling an Exception
Out of three of your codes only valid is rescue ErrorType1, ErrorType2 => ex. Others will give you syntax error.
Hierarchy(partial) :
StandardError
|
IndexError
|
KeyError
You can specify the error class names as arguments to the rescue list,in any order.On runtime ruby will pick up the correct one from the list. Look the code below :
begin
a = {}
a.fetch(:b)
rescue StandardError,KeyError,IndexError => e
p e.class
end
# >> KeyError
begin
a = {}
a.fetch(:b)
rescue KeyError,StandardError,IndexError => e
p e.class
end
# >> KeyError
If you think,you would tell Ruby interpreter on runtime, which one to match first using paren from the argument list,Ruby will not allow you to do so,in return it will throw to you syntax error. Same also for below :
begin
a = {}
a.fetch(:b)
rescue StandardError => e1
p e1.class
rescue IndexError => e2
p e2.class
rescue KeyError => e3
p e3.class
end
# >> KeyError
Note: If we want to catch more exception classes, we can just write them in line. When we want to handle different errors differently, we can specify several rescue clauses.Ruby Hacking Guide

What does the "=>" in "rescue Exception => e" do?

Given the example:
def method_of_doom
my_string = "I sense impending doom."
my_string.ah_ha_i_called_a_nonexistent_method
rescue NoMethodError => e:
puts "PROBLEM: " + e.to_s
rescue Exception:
puts "Uhh...there's a problem with that there method."
end
On the line where it says:
rescue NoMethodError => e:
What is the '=>' doing?
How is it different than this usage:
module FighterValues
BAMBOO_HEAD = { 'life' => 120, 'hit' => 9 }
DEATH = { 'life' => 90, 'hit' => 13 }
KOALA = { 'life' => 100, 'hit' => 10 }
CHUCK_NORRIS = { 'life' => 60000, 'hit' => 99999999 }
def chuck_fact
puts "Chuck Norris' tears can cure cancer..."
puts "Too bad he never cries."
end
end
module ConstantValues
DEATH = -5 # Pandas can live PAST DEATH.
EASY_HANDICAP = 10
MEDIUM_HANDICAP = 25
HARD_HANDICAP = 50
end
puts FighterValues::DEATH
→ {'life'=>90,'hit'=>13}
puts ConstantValues::DEATH
→ -5
The Hash Rocket is a Syntactic Token
The hash rocket is actually a syntactic token. You can find the token in the grammar defined by ext/ripper/ripper.y:
%token tASSOC /* => */
In other words, Ripper uses the hash rocket to associate things.
How tASSOC is Used
In general, this token is used in hash literals to associate a key with a value. For example:
{ :e => 'foo' }
associates the string literal foo with the symbol :e. This common usage is why people tend to think of the hash rocket as solely a hash-related construct.
On the other hand, the following associates a variable with an exception:
rescue => e
In this case, rather than associating a key with a value, Ripper is associating the variable e with the implied StandardError exception, and uses the variable to store the value of Exception#message.
Further Reading
If you understand tokenizers, lexers, and parsers, ripper.y and the various contents of ext/ripper/lib/ripper are instructive. However, on page 19 of Ruby Under a Microscope, Pat Shaughnessy warns:
Ruby doesn’t use the Lex tokenization tool, which C programmers commonly use in conjunction with a parser generator like Yacc or Bison. Instead, the Ruby core wrote the Ruby tokenization code by hand.
Just something to keep in mind when you're trying to grok Ruby's grammar at the source code level.
There are a bunch of good links on the Ruby Info page.
It depends on context.
In the context of a rescue it means:
"Assign the exception object to the variable e."
This is how it can be used as e.to_s later.
In a Hash literal it means:
A pair, represented by key=>value.
Here is a Hash literal is created from two pairs: {:name => "Fred", :age => 20}
(Ruby 1.9/2.0+ also allows {name: "Fred", age: 20} syntax, where name and age refer to Symbols.)
In a String, it is what it is:
"=>Whee!".
In this case puts FighterValues::DEATH, is equivalent to puts FighterValues::DEATH.to_s. That is, the output displayed comes from a string. Consider this: puts "{a => b}".

Resources