trying to add a variables in Ruby - ruby

I'm on day one of Ruby and I can't do the most basic of things. The code below is a sample of what I am trying to do. I simply need to add the user input wit the variable. I keep getting a "can't convert float into string" error message.
The more I research a solution, the more it steers me in a different direction. Recasting variables should be pretty simple. I don't understand what i'm doing wrong.
var1 = Float("9.99")
puts "enter in your quantity"
quantity1 = gets + var1
puts "quantity1"

gets returns a string, so you need to cast it to something Numeric in order to add a float to it.
quantity = gets.to_f + var1
will work, but I suggest that you'll do some more reading.
Also you can assign var1 like this: var1 = 9.99

gets stands for get string. You need to convert that string to an integer or a float using the method .to_i (to integer) or .to_f (to float).
I would do this:
var1 = 9.99
puts "enter in your quantity"
quantity1 = gets.to_f + var1
puts quantity1
Note you don't have to specify when a variable is "Float" if you use the decimale separator when you are declaring it. you can see this typing
puts var1.class
it will return Float

Related

Increment by 1 in while loop when string interpolation is used in Ruby

below is my scenario wherein i need to Increment by 1 in while loop when string interpolation is used in Ruby
When i do this
$min_value = 1
$max_value = 3
while $min_value < $max_value do
$url = "https:abcd.com?page=#{$min_value}&per_page=#{$max_value}"
puts $url
$min_value += 1
end
I get result like this below, which is perfect
https:abcd.com?page=1&per_page=3
https:abcd.com?page=2&per_page=3
But i want to use the $url outside the loop as a parameter
$min_value = 1
$max_value = 3
$url = "https:abcd.com?page=#{$min_value}&per_page=#{$max_value}"
while $min_value < $max_value do
$test = eval('$url')
puts $test
$min_value += 1
end
and i get wrong result
https:abcd.com?page=1&per_page=3
https:abcd.com?page=1&per_page=3
expected result is
https:abcd.com?page=1&per_page=3
https:abcd.com?page=2&per_page=3
how can i make this string interpolation of $min_value be increment. As my requirement is to keep the $url outside the loop as user will give this information
I suggest you avoid using eval on a string defined with single quotes. The conventional approach is the following.
min_value = 1
max_value = 3
fmt = "https:abcd.com?page=%s&per_page=%s"
(min_value..max_value-1).each { |n| puts sprintf(fmt, n, max_value) }
https:abcd.com?page=1&per_page=3
https:abcd.com?page=2&per_page=3
The operative line could instead be written:
(min_value..max_value-1).each { |n| puts fmt % [n, max_value] }
or
fmt1 = fmt + "\n"
#=> "https:abcd.com?page=%s&per_page=%s\n"
(min_value..max_value-1).each { |n| printf(fmt1, n, max_value) }
See Kernel#sprintf, String#% and Kernel#printf.
You should use global variables only when absolutely necessary, which often is never. Use instance variables only when a local variable will not do. I've made min_value, max_value and fmt all local variables because there is no suggestion by the question that their values are needed beyond the immediate task.
Generally, you should use loop structures while, until and loop only when the number of iterations is not known in advance. Here I've just iterated over a range.
Note that (min_value..max_value-1) could be replaced with (min_value...max_value). I only use three-dot ranges when the end of an infinite range is to be excluded. Mixing two- and three-dot ranges (in my opinion) makes code harder to read and results in more coding errors.
Change the $url to below:
$url = '"https:abcd.com?page=#{$min_value}&per_page=#{$max_value}"'
The reason your code is not working is because $url is already evaluated as string and you are trying to eval again. And, remove single quotes in eval method.
Final code:
$min_value = 1
$max_value = 3
$url = '"https:abcd.com?page=#{$min_value}&per_page=#{$max_value}"'
while $min_value < $max_value do
$test = eval($url)
puts $test
$min_value += 1
end
First, Refactor to Block-Local Variables
You've constructed a very non-idiomatic loop and applied some inconsistent formatting. As a result, you may be obscuring the fact that your interpolation is happening before you enter the loop, which means that Kernel#eval won't resolve the way you expect even if your string were properly quoted. The string is therefore never updated.
A refactoring that avoids global variables and eval looks like this:
starting_page = 1
items_per_page = 3
starting_page.upto(items_per_page) do |page|
url = "https://abcd.com?page=#{page}&per_page=#{items_per_page}"
puts url
end
This yields your expected results:
https://abcd.com?page=1&per_page=3
https://abcd.com?page=2&per_page=3
https://abcd.com?page=3&per_page=3
By defining a block-local variable (e.g. page) you also prevent unintended changes outside the block formed by Integer#upto. Understanding scope gates in Ruby has a steep learning curve, but it's often very helpful in avoiding subtle (or not-so-subtle) bugs in your code.
Next, Define a Format String Outside Your Loop
If you want to move the url variable outside the block, you will still need to generate a new string inside the loop. Eval is not ideal for this, although it can work if you fix your quoting. A better approach is to use Kernel#printf or Kernel#sprintf with a format string, depending on whether you want the output on an IO object or as a return value. For example:
starting_page = 1
items_per_page = 3
format_string = "https://abcd.com?page=%d&per_page=%d\n"
starting_page.upto(items_per_page) do |page|
printf format_string, page, items_per_page
end
This will print the same values to standard output as the loop with interpolation, but the string holding the format of the URL is now defined outside the loop while the %d placeholders in each string are replaced at runtime.

The code always outputs "not"

The following code always outputs "not":
print "input a number please. "
TestNumber = gets
if TestNumber % 2 == 0
print "The number is even"
else
print "The number is not even"
end
What is going wrong with my code?
The gets() method returns an object of type String.
When you call %() on a String object, the return value is a new String object (usually it changes the text. You can read more about string formatting here).
Since there are no String objects that == 0, the if/else will always take the same path.
If you want to use the return value of gets() like a number, you will need to transform it into one first. The simplest approach is probably to use the to_i() method on String objects, which returns a new 'Integer' object. If you're doing something where the user input will not always be an integer (e.g. 3.14 or 1.5), you might need to use a different approach.
One last thing: in your example the result of gets() is saved into a constant called TestNumber. Constants are different to normal variables, and they will probably cause problems if you're not using them intentionally. Normal variables don't start with capital letters. (You can read more about ruby variables here). In ruby you need to write you variable names like this: test_number.
I suspect your Testnumber variable might be interpreted as a string during the operation. make sure the testnum is converted to an integer first even if you put in say 100 it could be its being interpreted as the stirng "100" and not the integer 100.
A similar issue can be found here: Ruby Modulo Division
You have to convert TestNumber from string to integer, as your input has linefeed and/or other unwanted characters that do not match an integer.
Use TestNumber = gets.to_i to convert to integer before testing.

When do you have to use #{} while referring to variables in Ruby?

Sometimes if I've defined a a variable, for example
xyz="example"
and I'd like to refer back to xyz, I can either type xyz or #{xyz} in statements/loops etc.
My question is when do I use xyz and when do I use #{xyz}? And how do they differ?
#{} allows you to use any Ruby expression (not necessarily a variable) inside an interpolating quote (doubly-quoted strings, regular expressions...). It will evaluate the expression, convert the result to a string using the to_s method, then insert ("interpolate") the result into the string at that spot.
For example, if you have a string "Hello, apollo!" and want to replace the apollo with the contents of a variable, you could say "Hello, #{name}!".
You could even put a whole program inside a string:
"One plus two equals #{
def last_name_by_first_name(last_name)
People.find_by_last_name(last_name).first.first_name
end
find_by_last_name('Jack')
}!"
or
"#{a = 1} + #{b = 2} = #{a + b}"
(But please don't do that, it's a horrid way to write code. Sticking with variable look-ups and simple function calls should be enough for most purposes.)
Anywhere outside of a string (or other interpolating quote), #{} is an error.

Money format when printing number

def percent_of
puts "What is the number?"
number = gets.chomp.to_f
puts "What is the percent?"
percent = gets.chomp.to_f
total_percent_of = number * percent.to_f
puts " #{percent}% of #{number} is #{total_percent_of.to_i}."
end
Ok so this is a very simple percent of program and works fine. But one thing I don't like is that whenever the console prints out the total it looks like the following example: 75.0% of 417 is 31275.
Now is there any way I could get the total to type out in decimal/money form? Like it should be 312.75 or something like that. Please try and keep your answers simple, I'm new to Ruby. Thank you!
First you need to fix your math. 75% is equal to 75/100 so you want
total_percent_of = number * percent / 100.0
Next you need a format string to ensure that total_percent_of is always printed with the correct number of decimals:
sprintf " #{percent}%% of #{number} is %.2f", total_percent_of
(you need the %% after percent because percent signs have special meaning to sprintf). See the documentation for more information about string formatting.

Can't convert String into Integer (TypeError)

I am learning Ruby
I am trying to create a simple script that will convert a given number to roman numerals (old style roman numerals)
I am unable to understand why I get the "can't convert String into Integer (TypeError)"
def convert_to_roman number
romans_array = [[1000,'M'],[500,'D'],[100,'C'],[50,'L'],[10,'X'],[5,'V'][1,'I']]
converted_array = []
romans_array.each do |rom_num|
num = rom_num[0]
letter = rom_num[1]
if number > num
times = number / num
roman_letter = letter*times
converted_array.push(roman_letter)
number = number % num
end
end
converted_array.join()
end
number = ''
puts 'please write a number and I will convert it to old style Roman numerals :)'
puts 'p.s. to exit this program simply hit enter on an empty line, or type 0 and enter :)'
while number != 0
number = gets.chomp.to_i
puts convert_to_roman number
end
My code is at:
https://github.com/stefanonyn/ruby-excercises/blob/master/roman_numerals.rb
You will see that at the end of the file commented out there is an old revision of the code, which actually does work but has a lot of repetition.
I would appreciate if someone could clarify why I get the error described above.
Please don't write the code for me, I am trying to learn Ruby, I would appreciate just some support in moving to the next step.
Thank you very much!
You are missing a comma in your array
romans_array = [[1000,'M'],[500,'D'],[100,'C'],[50,'L'],[10,'X'],[5,'V'][1,'I']]
^ here
This error is definitely not all that helpful, but the reason that it is appearing is that to the interpreter it looks like you are attempting to access a range of indexes in the [5,'V'] array for the last element. However the index's that are being provided go from 1 to 'I' which of course makes no sense. If it had been written [5,'V'][1,1] the last element of the array would be ['V'], which might have been even more confusing to debug!

Resources