Integer Range in Ruby - 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

Related

Ruby Block syntax

I was going through some code I found online and found the following
def change input
('a'..'z').map { |letter| input.downcase.include?(letter) ? '1' : '0' }.join
end
I understand what this code is doing. It will take a string, check if the string contains each letter of the alphabet and return 1 if true and 0 if false.
However I am unfamiliar with this bit of syntax:
?(letter) ? '1' : '0' }
I know that a question mark is usually used to indicate that the method will return a boolean result. But I am insure why there is a second question mark after the argument.
Also, I understand that this will return 1 if true and 0 if false. Is that what this colon represents. Is it always ok to use a colon like this if the result of the method in the block will be a boolean?
The format boolean_expression ? option_a : option_b is called a ternary operator. It is short for
if boolean_expression
option_a
else
option_b
end
The first question mark is part of the #include? method
The expession condition ? if_true : if_false is called a ternary operator, which is shorthand for
if condition
if_true
else
if_false
end

ruby check whether string in csv will be mistaken for a date (in excel)

I have a function in my Rails app that creates a csv. When the user opens that csv in Excel many times there are fields that excel changes like:
1-3
becomes
Jan-3
I can easily overcome this issue by using the solution outlined here: http://www.excelforum.com/excel-general/491295-opening-csv-how-to-tell-excel-string-is-not-a-date.html
csvarray.push('="'+result_item.send(column).to_s+'"')
The field in the csv becomes:
="1-3"
But would like to convert only the fields that Excel gets wrong and not all the fields.
I started by doing a:
.match(/-/)
but I am wondering if there is a better and more exclusive way to find the offending fields.
Any ideas?
Ruby 1.8.7, Rails 3.2.12
EDIT: Combining both #Agis and #Mori's answers seems to cover most of the examples I have come across:
def col_is_date?(value)
(!!(Date.parse(value) rescue nil)) || ((value =~ /\A\d{1,2}-\d{1,2}\z/) === 0)
end
I am not sure who to award the "correct" answer to...
EDIT 2: regarding the two correct answers I defer to: https://meta.stackexchange.com/questions/196341/combination-of-two-answers-is-the-correct-answer
def col_is_date?(value)
!!(Date.parse(value) rescue nil)
end
You should be explicit and specify what values you want to allow:
regexp = /\A\d{1,2}-\d{1,2}\z/
'1-1' =~ regexp # => 0
'Jan-1' =~ regexp # => nil
This regular expression will match everything that starts with one to two digits, followed by a -, followed (and ending) with one to two digits.
Per my edits I found the combination of the two answers to be what I needed or "correct" and again referring to this https://meta.stackexchange.com/questions/196341/combination-of-two-answers-is-the-correct-answer I believe the next step is to answer my own question with the combined answer.
def col_is_date?(value)
(!!(Date.parse(value) rescue nil)) || ((value =~ /\A\d{1,2}-\d{1,2}\z/) === 0)
end

Break in While Loop when Specific Input is Entered

I am trying to halt input from a user when their input is 42.
The correct answer on the website I'm working on is:
while line = gets
break if (/42/ =~ line)
x << line
end
The code I tried that does not work is:
while line = gets.chomp
break if (line == 42)
x << line
end
Why is this the case? Am I missing some limitations to what I can use in my if statement?
The problem is that 42 is an integer, but line is a string:
1.9.3p392 :001 > "42" == 42
=> false
So it's never the case that your if statement is getting triggered, because it's comparing two different kinds of things. Matching with a Regex fixes it, though it's looking for "42" to appear anywhere in the input (e.g. "3427"). I think what you meant to say was
while line = gets.chomp
break if (line == "42")
x << lineĀ 
end
In other words, break when the input is a string with the characters 4 and 2 in it.
I suspect it's because you're comparing a number to a string. The example uses a regular expression it appears. "42" == 42 will give you false in ruby.
<< is a method(Append) on Array or String class objects. But your x not holding any referencing to such objects. Thus you are getting undefined local variable or method 'x' for main:Object (NameError).
Try this instead(by fixing local variable x to hold a practical object and converting line value to Fixnum object:
x = "hi"
while line = gets.chomp
break if (line.to_i == 42)
x << line
end
This program will help you to halt input from a user when their input is 42.
until (line = gets.chomp).to_i == 42
x << line
end
This of course bypasses the if statement you were asking about.
Your limitation for the if is based solely on the fact that you are comparing a string that will always be a string to a number, and this will never be equal. (as others have mentioned)
So we must reconsider the conditional statement. In this case, I considered it "out of place" and moved the comparison to the 'while' loop, and then inverted it to an 'until' statement, to be able to positively express the condition to end the loop on. Whenever I see a 'break' in a loop, I try to get rid of that smell, as the condition to leave a loop should really be expressed in the loop condition if possible.
I hope this helps.

Checking character length in ruby

I got stuck in another situation: our users enter a text to be stored in a variable. The condition for that text is it can be allowed to enter only 25 characters, Now I have to write a regular expression which will check the condition, kindly help me out in this.
I think you could just use the String#length method...
http://ruby-doc.org/core-1.9.3/String.html#method-i-length
Example:
text = 'The quick brown fox jumps over the lazy dog.'
puts text.length > 25 ? 'Too many characters' : 'Accepted'
Ruby provides a built-in function for checking the length of a string. Say it's called s:
if s.length <= 25
# We're OK
else
# Too long
end
Instead of using a regular expression, just check if string.length > 25
Verification, do not forget the to_s
def nottolonng?(value)
if value.to_s.length <=8
return true
else
return false
end
end
You could take any of the answers above that use the string.length method and replace it with string.size.
They both work the same way.
if string.size <= 25
puts "No problem here!"
else
puts "Sorry too long!"
end
https://ruby-doc.org/core-2.4.0/String.html#method-i-size

RegEx in Ruby: Just one match?

I'm trying to figure out how to check if a string matches a regular expression, but I want to know if the entire string matches just once. Here's my code but it seems absurdly long
def single_match(test_me, regex)
ret_val = false
test = regex.match(test_me)
if (test.length==1 && test[0].length == test_me.length)
ret_val = true
end
return ret_val
end
is there an easier way to do this?
P.S. Here's the method I'm really trying to write, since people always seem to ask why I want the gun these days:
def is_int(test_me)
return single_match(test_me, /[0-9]*/)
end
Edit Thanks everybody. Here's where I'm really using it, but this regex stuff is always interesting to go through. Thanks for the great and educational answers.
You don't need to do this, your method can be replaced by using the regular expression of /^[0-9]*$/. The ^ tells it match start of a line and $ tells it match end of the line. So it will match: start of line, 0 to any in range of 0 to 9, and finally end of line.
def is_int(test_me)
test_me =~ /^[0-9]*$/
end
And you don't need the return statements, Ruby implicitly returns the last statement.
Edit:
It probably would be easier and look better to use the to_i instance method of String class.
def is_int(test_me)
test_me.to_i.to_s == test_me
end
Edit: (did some tests)
Comparing the performance between the two methods shows that .to_i.to_s == way is 5% faster. So it is up to personal preference to which ever looks better and if you want to handle leading zeroes.
To do what you really want should be even simpler
def is_int(test_me)
test_me.to_i.to_s == test_me
end
This?
def single_match(str, regex)
str.match(regex).to_s == str
end
To answer your original question, for the sake of people finding this page in a search, "scan" will return an array of matches, so if you want to find out how many times some regexp matches, e.g. how many runs of digits there are, you can do:
mystring.scan(/\d+/).size

Resources