Test variable for Numeric in one line - ruby-on-rails

I found this code on another thread.
def is_number? string
true if Float(string) rescue false
end
Instead of using a method to return true or false, I'd like to do this "is_numeric" test in one line, in an if statement. Can someone explain if this is possible? I'm getting errors at the moment both when the string variable is null and when it contains non-numeric characters.
if Float(string)
* do something
else
* do something else
end

if Float() is pointless code, since Float() will either return a truthy value or raise an error (based on my limited look at the source code - as of writing, you can follow the code path from line #2942). I'd suggest you're asking the wrong question/looking at the problem wrong (it'd be helpful to know what you're actually trying to achieve).
To do something with Float() on one line and avoid breaking code, use rescue as a statement modifier, as has been done in the is_number? method posted.
Float(string) rescue 0.0 # trying to emulate String#to_f!

Ensuring the phone number is 10 digits, numbers only, is quite simple.
PHONE_NUM_LENGTH = 10
string.length == PHONE_NUM_LENGTH && string.count('0-9') == PHONE_NUM_LENGTH
will return the true/false value representing this check. This is more efficient than a Regex.
The first part,
string.length == PHONE_NUM_LENGTH
checks whether the string is 10 characters long. The second,
string.count('0-9') == PHONE_NUM_LENGTH
checks whether it has exactly 10 numeric characters.

Related

Infinite loop bug in Lua

I'm new to this platform and I'm still learning to
program in Lua, so, if any newbie errors appear, forgive me.
The following code is from one of the functions in my project that reads the insert
of the user and validates whether or not it is a data of type "Number". If,
the loop will be broken and the function will return the user input, otherwise, the
program will ask the user to enter the data again:
function bin.readnum(text)
local insertion
if text == nil then text = "Text: " end
while (insertion == nil) do
insertion = nil
print(text)
insertion = io.read("number")
if insertion ~= nil then break end
end
return insertion
end
But, if the user enters a wrong data (string) the function prints the text
madly instead of asking the user to re-enter the data.
When io.read fails to parse the data it got into a number, it doesn't discard it, but instead leaves it in the buffer for the next call to it. That means that in your code, instead of letting the user enter something else, it'll just keep trying to parse the same non-number forever. To fix it, in your if insertion ~= nil then block, do io.read() right before break, to read and discard the whole invalid line.
In addition to what Joseph Sible said:
io.read("number") is wrong: 5.1 docs demand "*n" and 5.4 docs demand just "n" for reading numbers. It probably works nevertheless due to Lua just searching for the chars in the string.
I recommend just replacing insertion = io.read("number") withinsertion = tonumber(assert(io.read(), "EOF")) - this will read a line and try to parse it as a number; the assert gracefully deals with nil being returned by io.read for EOF.
You don't need to set insertion to nil, the later assignment will do that already if what was read is not a valid number.
Style: Consider replacing your explicit nil checks with truthiness checks and removing the parentheses around the while-condition. You don't need a break, you can immediately return the read number; finally, you can even replace the entire loop with tail recursion.
All in all I'd rewrite it as follows:
function bin.readnum(text)
print(text or "Text: ")
local num = tonumber(assert(io.read(), "EOF"))
if num then return num end
return bin.readnum(text)
end
or alternatively using a repeat-until loop:
function bin.readnum(text)
local num
repeat
print(text or "Text: ")
num = tonumber(assert(io.read(), "EOF"))
until num
return num
end

What is local name = value or 0 in lua?

What does this block of code do?
local name = value or 0
Please tell me that it makes it zero if nil and makes it value if not nil.
Short answer
yes
Looooong answer
You're right. While in other languages, the logical operators return either true or false, Lua (and some other languages) does something more clever:
When the first parameter of or is truthy, it evaluates to that value, if it's not, it evaluates to the second one. And does it the other way around: if its left-hand-side is falsey, it evaluates to that, otherwise it evaluates to its RHS.
Logically, this means that or evaluates to truthy if either operand is truthy and and evaluates to falsey if either of its operands is.
This is often used as an equivalent of
if value then
name = value
else
name = 0
end
And it effectively does the same. It is also often use to assign default values to variables like this:
function call(name)
name = name or "you"
print("Hey "..name.."! Come here for a moment!")
end
Note though, that this doesn't work
function alarm(real)
real = real or true
print "ALAAARM!"
if real then print "This is NOT a drill!" end
end
alarm(false)
This will always print "ALAAARM!" "This is NOT a drill!", because false is evaluated as falsey, so the or statement evaluates to its RHS, which is true. In this particular example, you would have to check explicitly if the argument is nil.
-- ...
real = (real == nil) and true or real
-- ...
This would work as intended, because only if real == nil, the and statement evaluates to true, and the or thus evaluates to its LHS. If real == nil is false, then the and evaluates to that, thus the or statement evaluates to its RHS (because its LHS is false).
It's also worth mentioning that both and and or are short-circuited. What this means is:
function foo(bar)
print(bar)
return bar
end
io.write "First: "
local A = foo(nil) or foo(false)
io.write "Second: "
local B = foo(true) or foo(true)
This will print "First: nil false" on the first two lines, but then "Second: true" on the third line. The last call to foo is not even executed, because at that point the or statement already knows it's going to return its left operand.

My code doesn't do anything

game:GetService("Players").PlayerAdded:connect(function()
for _, Player in pairs(game:GetService("Players"):GetPlayers()) do
Player.Chatted:connect(function(msg)
if string.sub(msg,1,5) == "oofergang" then
Player:Kick("no no no cringe baby")
end
end)
end
end)
return ''
How do I fix this? It doesn't do anything, no errors nothing.
Your issue seems to be in your string.sub() usage. (I'm assuming this is Roblox, which I don't know much about).
The string.sub(a, b, c) method takes the substring of the string a, starting from index b and going to index c.
Your problem is that you're trying to get the substring from characters 1-5. Character 1 is the first character and character 5 is the 5th character in the string. Your if block is checking the first 5 characters of the player's message. The issue is that the string you're comparing it to, "oofergang", is longer than 5 characters.
If the player does correctly type oofergang, the string.sub() that you're using will output oofer, which is the first 5 characters of the message. Essentially, this is what the program will see when running:
if "oofer" == "oofergang" then
oofer is never going to equal oofergang.
If you want to check if the player starts their message with oofergang then you should use the following if block instead:
if (string.sub(msg, 1, 9) == "oofergang") then
--Whatever you want to do here, in your case kick the player
end
EDIT: As suggested, the following code allows you to find a string within another string ANYwhere, not just a the start:
if (string.find(msg, "oofergang")) then
--Whatever you want to do here, in your case kick the player
end

Finding the number of digits in a number restricted number of tools since I am a Python beginner

def digits(n):
total=0
for i in range(0,n):
if n/(10**(i))<1 and n/(10**(i-1))=>1:
total+=i
else:
total+=0
return total
I want to find the number of digits in 13 so I do the below
print digits(13)
it gives me $\0$ for every number I input into the function.
there's nothing wrong with what I've written as far as I can see:
if a number has say 4 digits say 1234 then dividing by 10^4 will make it less than 1: 0.1234 and dividing by 10^3 will make it 1.234
and by 10^3 will make it 1.234>1. when i satisfies BOTH conditions you know you have the correct number of digits.
what's failing here? Please can you advise me on the specific method I've tried
and not a different one?
Remember for every n there can only be one i which satisfies that condition.
so when you add i to the total there will only be i added so total returning total will give you i
your loop makes no sense at all. It goes from 0 to exact number - not what you want.
It looks like python, so grab a solution that uses string:
def digits(n):
return len(str(int(n))) # make sure that it's integer, than conver to string and return number of characters == number of digits
EDIT:
If you REALLY want to use a loop to count number of digits, you can do this this way:
def digits(n):
i = 0
while (n > 1):
n = n / 10
++i
return i
EDIT2:
since you really want to make your solution work, here is your problem. Provided, that you call your function like digits(5), 5 is of type integer, so your division is integer-based. That means, that 6/100 = 0, not 0.06.
def digits(n):
for i in range(0,n):
if n/float(10**(i))<1 and n/float(10**(i-1))=>1:
return i # we don't need to check anything else, this is the solution
return null # we don't the answer. This should not happen, but still, nice to put it here. Throwing an exception would be even better
I fixed it. Thanks for your input though :)
def digits(n):
for i in range(0,n):
if n/(10**(i))<1 and n/(10**(i-1))>=1:
return i

BigDecimal to Currency with -0.0

I am working on reports for a website and I am currently thinking of what would be the best way to handle BigDecimal -0.0's.
The database I'm working with has a lot of them. When these -0.0's are put through number_to_currency(), I get "$-0.00". My format for negative numbers is actually "-$x.xx", so note that number_to_currency is not formatting it as a negative number (otherwise there would also be a negative sign in front of the dollar sign), but for some reason the negative sign is being translated along with the 0.
Right now my solution is to do this every time I get an amount from the database:
amount *= -1 if amount == 0 && amount.sign == -1
This changes the -0.0 to a 0.0. It's simple enough, but I can't help but wonder if there is a better solution, or something on BigDecimals or number_to_currency to handle this situation that I'm just not finding.
That is so because the number is converted into a string to be displayed. And:
# to_d converts to BigDecimal, just FYI
"-0".to_d.to_s #=> "-0.0"
Therefore you will have to make it a 0 yourself. But the sign-checks are redundant - a simple comparison with 0 will do the trick:
bdn = "-0".to_d # or BigDecimal.new("-0")
value = bdn.zero? ? 0 : bdn
number_to_currency(value, other_options)
However, you wouldn't want to manually add this check everywhere you're calling number_to_currency. It would be more convenient to create your own modified_number_to_currency method, in your ApplicationHelper, like so:
def modified_number_to_currency( number, options )
value = number.zero? ? 0 : number
number_to_currency(value, options)
end
And then use modified_number_to_currency instead of number_to_currency.
Alternatively, you could overwrite number_to_currency and have it call super in the end. That might also work but I'm not 100% certain.
Coming to your check specifically:
amount *= -1 if amount == 0 && amount.sign == -1
It should simply be:
amount = 0.to_d if amount.zero? # the to_d might or might not be required

Resources