Ruby break expression acting weird [duplicate] - ruby

This question already has answers here:
No increment operator (++) in Ruby? [duplicate]
(3 answers)
Closed 6 years ago.
require 'csv'
i = 0
CSV.foreach("survdata.csv", headers: true) do |row|
puts row
i++
if i > 1 then
break
end
end
This looks so simple, and yet it doesn't run. Can you see why I am getting:
/mydev/surveyresult/surveyresult.rb:11: void value expression

Ruby does not support i++ syntax as a shortcut to i+=1. See "Why doesn't Ruby support i++ or i-- (increment/decrement operators)?" for more information why.
You can fix your code like this:
require 'csv'
i = 0
CSV.foreach("survdata.csv", headers: true) do |row|
puts row
i = i+1
if i > 1 then
break
end
end
More information on the error message (thanks sawa):
Ruby does actually support i++ syntax. If it is followed by x, it is interpreted as unary operator + applied to x, whose result passed as an argument to i+. In your example, if i > 1 then; break; end does not return any value, hence the error message "void value expression".

Ruby doesn't have an increment operator the last time I looked.
In place of
i++
do
i += 1

Yes. It is because the:
if i > 1 then
break
end
part breaks, which does not have a return value (within the code block in question). And you cannot apply the unary operator +# to something that lacks a value, nor can i.+ take the return value of such as an argument.

Related

What does "!" symbol mean in Ruby language [duplicate]

This question already has answers here:
Exclamation points before a variable in Ruby
(3 answers)
Closed 2 years ago.
For example: what is this saying:
if !result[movie[:studio]]
result[movie[:studio]] = movie[:worldwide_gross]
else
result[movie[:studio]] += movie[:worldwide_gross]
end
i += 1
end
This is a solution to manipulating an NDS, or rather getting some information from an NDS and I can't seem to find what the !result means.
The ! negates the element. So if result[movie[:studio]] is truthy then !result[movie[:studio]] is the opposite, falsy. Your conditional statement is basically saying that if there is no value for the studio key then give it a value of movie[:worldwide_gross], otherwise add to the current value.
If you do not like the ! you could consider using unless instead or swap the order of the conditional.
if result[movie[:studio]]
result[movie[:studio]] += movie[:worldwide_gross]
else
result[movie[:studio]] = movie[:worldwide_gross]
end
! negates the element as it was already mentioned.
So, !true => false
So if you do
if !hungry
do x
end
You will execute X if you are not hungry.
It might also be used on null. So you can use it to check if "not null". This might be the use case that you're seeing.

The syntax about While loop in Ruby

I'm practicing the While Loop in Ruby and got a basic example as below
i = 3
while i > 0 do
print i
i -= 1
end
My question is why I can't interchange do..end with {} as if I rewrite the above code as below it doesn't work anymore
i = 3
while i > 0 {
print i
i -= 1
}
However, it seems to work without the first "do"
i = 3
while i > 0
print i
i -= 1
end
Could anyone explain the rule or redirect me to the right resource? Thx!
As you said do is optional for while loop. While keyword is enough to define a block which is finished with end like any other block in ruby. In addition, end is mandatory for while block.
If you want to use while on just one line you can do such as below:
i = 0
i += 1 while i < 10
While mandatory needs end in Ruby.
Syntax example
do is optional and can be omitted.
So, it is not the case where pair do - end can be replaced with {}

block syntax difference causes "LocalJumpError: no block given (yield)" [duplicate]

This question already has answers here:
Code block passed to each works with brackets but not with 'do'-'end' (ruby)
(3 answers)
Closed 8 years ago.
Saw a strange case come up, trying to figure out what is happening here:
> def test
> p yield
> end
=> nil
> test { 1 }
1
=> 1
> p test { 1 }
1
1
=> 1
> p test do
> 1
> end
LocalJumpError: no block given (yield)
The parser recognizes this
p test do
1
end
as this
p(test) do
1
end
The block is passed to p, not test. Therefore, yield can't yield and raises that error.
do and {} to denote blocks attached to methods are not completely interchangeable.
p test do
1
end
Precedence is screwing with you. This is actually this:
p(test()) do
1
end
So the block is getting passed to p, not test.
{} has higher precedence than do, and so binds more tightly to the syntactically closer method. This is also true for other ruby keywords that have symbolic equivalents, such as and/&& and or/||, which is why the symbols are usually recommended over the words.

Why does a range with invalid arguments sometimes not cause an argument error?

The following code causes an argument error:
n = 15
(n % 4 == 0)..(n % 3 == 0)
# => bad value for range (ArgumentError)
which I think is because it evaluates to:
false..true
and different types of classes are used in range: TrueClass and FalseClass. However, the following code does not raise an error. Why is that? Does Enumerable#collect catch it?
(11..20).collect { |i| (i % 4 == 0)..(i % 3 == 0) ? i : nil }
# => no error
Added later: If fcn returns 15, then only first half of range is evaluated
def fcn(x)
puts x
15
end
if (fcn(1) % 4 == 0)..(fcn(2) % 3 == 0); end
# => 1
but if we change return value to 16 then input will be
# => 1
# => 2
It's strange, because in this case expression evaluates to
true..false
And such kind of range is invalid according to sawa's answer below.
Then in first case (with def's return value 15) we have only partial range with no ending part? It's so strange :)
In Ruby if start..finish is a flip-flop, a special syntax for writing fast and obscure scripts. It is usually used in loops:
while input = gets
puts "Processing #{input.inspect}" if input =~ /start/ .. input =~ /end/
end
When the first condition is true, the whole condition is considered true on every consecutive execution until the second condition evaluates to true. You can play with the above script to get the idea. Here is my input & output:
foo
start
Processing "start\n"
foo
Processing "foo\n"
bar
Processing "bar\n"
end
Processing "end\n"
foo
bar
start
Processing "start\n"
Note that if the condition is not started Ruby doesn't evaluate the finishing condition because this is useless to do so.
Although it does not make much sense to use this outside of loops, Ruby is not restricting that.
>> if nil..raise; :nothing_gonna_happen; end
=> nil
First of all, note the following valid and invalid literals:
true..true # => valid
false..false # => valid
true..false # => invalid
false..true # => invalid
So the question reduces to why the expressions that evaluate to false..true and true..false become valid when embedded in a loop condition. According to documentation, a range literal in loop condition does not actually create a range. It rather has a special meaning akin to sed and awk. That is, the truth of the start of a range initiates the loop and truth of the end of the range terminates it. Some examples found here.

Integer Range in Ruby

I'm a newbie to Ruby, I have a problem following the Poignant Guide to Ruby:
Does this expression return true?
2005..2009 === 2007
But I don't know why I got this warning message from the following code
wishTraditional.rb:4: warning: integer literal in conditional range
code:
def makTimeLine(year)
if 1984 === year
"Born."
elsif 2005..2009 === year
"Sias."
else
"Sleeping"
end
end
puts makTimeLine(2007)
and the it return Sleeping, which is wrong and should be the Sias
BTW what does the two dots mean? How can I find more information about it?
I think you better use something like that :
elsif (2005..2009).include?(year)
Here is the documentation about Ruby ranges
Update: if you insist on using ===, you should enclose the range in parentheses:
elseif (2005..2009) === year
For independent expressions, yes, you'll need to put range literals in parentheses.
But your if/elsif chain would be cleaner as a case statement, which uses === for comparison:
def makTimeLine(year)
case year
when 1984
"Born."
when 2005..2009
"Sias."
else
"Sleeping"
end
end

Resources