!! (double bang) meaning in Ruby [duplicate] - ruby

This question already has answers here:
Why would you use a !! operator
(5 answers)
Closed 6 years ago.
What does !! mean in the following method?
def include?(record)
!!#association.include?(record)
end

It casts a variable into type boolean and determine its truthy or falsy value
For example:-
# Numbers...
!!1 # => true
!!0 # => true
# Numbers as strings...
!!'1' # => true
!!'0' # => false
# Truthy strings (case insensitive)...
!!'true' # => true (alias: 't')
!!'false' # => false (alias: 'f')
!!'yes' # => false (alias: 'y')
!!'no' # => false (alias: 'n')
# Booleans...
!!true # => true
!!false # => false
# Nil...
!!nil # => false

It helps you get boolean results.
For Example:
a = nil
!a
#=> true
!!a
#=> false
Similarly
a = 1
!a
#=> false
!!a
#=> true

The double exclamation mark will convert the result to a boolean value so that, in this case, if #assication.include?(record) returns nil that will get converted to false.

Related

Trying to use .reduce to return true if there are truthy values else false if there are falsey values

Trying to use .reduce for course lesson... here is what they want my method to do:
describe "reduce_to_all_true returns true when all values are truthy" do
it "reduces correctly" do
source_array = [1, 2, true, "razmatazz"]
expect(reduce_to_all_true(source_array)).to be_truthy
end
end
describe "reduce_to_all_true returns false when any value is false" do
it "reduces correctly" do
source_array = [1, 2, true, "razmatazz", false]
expect(reduce_to_all_true(source_array)).to be_falsy
end
end
I am having a hard time understanding this...here is my code:
def reduce_to_all_true(source_array)
source_array.reduce { |beTrue| if beTrue == true; p true; else p false end}
end
The error I get:
1) my own reduce-like methods reduce_to_all_true returns true when all valuesare truthy reduces correctly
Failure/Error: expect(reduce_to_all_true(source_array)).to be_truthy
expected: truthy value
got: false
Any help/explanation would be much appreciated!
You need to understand the difference between "truthiness"/"falsiness" and being true/false.
Ruby would evaluate everything that is not nil or false as truthy, so you can write:
puts 1 if 1
and it will puts 1.
In this assignment you're asked to use truthiness, so instead of comparing to true you can use ruby to do the conversion for you using double negation !!:
pry> [1, "2", nil, true, false].map{|e| !!e}
=> [true, true, false, true, false]
Also note that a block in reduce accepts two params - one is the current element and another one is accumulator - the result of interating over previous elements. Use both in the block, otherwise you'll be returning result depending only on the last element of the array.
Alternative answer:
For those not doing this for a course, where the point is specifically to explore using reduce, the all? method on arrays may be useful:
[true, 1, "2"].all? # => true
[true, 1, "2", false].all? # => false
Further discussion of the above:
Of note to those comparing this with using and more directly: this does not do "short-circuiting" — that is, all elements in the array will get evaluated:
[false,puts("test"),false].all?
test # printed
# => false # returned
Compare:
false and puts("test") and false
# => false # returned
# [nothing gets printed]
Of course, this really all happens before #all? is even called... it's as if one had done this:
arr = [false,puts("test"),false]
test # printed
arr
# => [false, nil, false] # value of arr
arr.all?
# => false # returned
Still, I thought it was worth noting, as some may expect a short-circuiting behavior.

Check if a string contains only digits in ruby

I have a string which is passed as a parameter to a function. Here, I want to check if the string contains only numbers. So I had a check like below:
def check_string(string)
result = false
if string.to_i.to_s.eql? string
result = true
end
result
end
But the problem arises when a string starts with 0. In that case, a false is returned.
check_string('123') #=> true
check_string('0123') #=> false
How can I solve this issue?
You can try the following
def check_string(string)
string.scan(/\D/).empty?
end
It would be truthy if string contains only digits or if it is an empty string. Otherwise returns false.
A number can be negative, or a float. So if these are allowed, consider this solution:
def is_numberic?(str)
str == "#{str.to_f}" || str == "#{str.to_i}"
end
some input which evaluate to true
pry(main)> is_numberic? '5'
=> true
pry(main)> is_numberic? '58127721'
=> true
pry(main)> is_numberic? '58127721.737673'
=> true
pry(main)> is_numberic? '0'
=> true
pry(main)> is_numberic? '1818'
=> true
pry(main)> is_numberic? '0.1'
=> true
pry(main)> is_numberic? '0.0'
=> true
pry(main)> is_numberic? '11.29'
=> true
pry(main)> is_numberic? '-0.12'
=> true
pry(main)> is_numberic? '-29'
=> true
the input which evaluate to false
pry(main)> is_numberic? '10 years'
=> false
pry(main)> is_numberic? '01'
=> false
pry(main)> is_numberic? '00'
=> false
pry(main)> is_numberic? '0.10'
=> false
pry(main)> is_numberic? ''
=> false
As you can see, there're several cases which probably should be supported, eg '0.10', but are not. In this case, the permitted input is '0.1'.
def check_string(str)
str !~ /\D/
end
check_string '123'
#=> true
check_string ''
#=> true
check_string '1a2'
#=> false
this is my proposition for detecting if it's a float number
def check(string)
scan = string.scan(/\D/)
scan.size == 0 || (scan.size == 1 && scan.first == ".") # or "," depend on your separator
end
example of use:
check("123") => true
check("12.3") => true
check("12e3") => false
check("12.3.2") => false
EDIT: 2023
After some years i see this is the most compact solution:
def check_string(str)
str.scan(/\D/).empty?
end
You can use Regexp for it:
def check_string(string)
raise 'Empty string passed' if string.empty?
/\A\d+\z/ === string
end
check_string '123'
#=> true
check_string '0123'
#=> true
check_string '0'
#=> true
We can also use the "match" function to do this.
"1234".match(/\D/)
#=> nil
"1234foo".match(/\D/)
#=> #<MatchData "f">
match (String) - APIdock
I think we should use the regex to find this.
it will work for the below scenarios
"3.0"
"av3"
"3"
is_numeric = false if option.option.match?(/[^0-9.]/)
If anyone is searching for another way to determine if string is numeric -> is to use "is_a? Numeric". Is_a? reference documentation
"namaste".is_a? Numeric
=> false
6.is_a? Numeric
=> true
str1 = "foo"
str2 = 9
str1.is_a? Numeric
=> false
str2.is_a? Numeric
=> true
You can also use:
7.is_a?(Numeric)
=> true
"too".is_a?(Numeric)
=> false
Basically it's determining if a class is a type of class object. I just found this and thought I would share.

String includes another string or regex (Ruby)

I need to check if given String includes a string or regex. If it does, it should return true, otherwise - false. How can I do it?
I have:
def method(string)
if #text.match(/#{string}/)
true
else
false
end
end
But I'm not sure if it's a proper way.
Consider this:
#text = 'foobar'
def method1(string)
if #text.match(/#{string}/)
true
else
false
end
end
That can be reduced to:
def method2(string_or_regex)
if #text[string_or_regex]
true
else
false
end
end
String's [] method allows us to pass in a string or a pattern. If it's a string, the method uses it for a fixed-string/in-string search. If a pattern is passed in it returns the matching text.
However, Ruby is more friendly than this. We don't have to tell it to return a true or false value conditionally. In Ruby, a nil or false value is treated as false, and anything else is "truethy". We can convert a value to true/false using !!, which is double boolean "not":
true # => true
'foo' # => "foo"
false # => false
nil # => nil
!true # => false
!'foo' # => false
!false # => true
!nil # => true
!!true # => true
!!'foo' # => true
!!false # => false
!!nil # => false
Knowing that, and that String's [] returns a nil if not found, or the matching text if found:
'foo'['foo'] # => "foo"
'foo'['bar'] # => nil
we can reduce the original method to:
def method3(string_or_regex)
!!#text[string_or_regex]
end
Here's what happens testing each of the methods above:
method1('foo') # => true
method1('baz') # => false
method2('foo') # => true
method2(/foo/) # => true
method2('baz') # => false
method2(/baz/) # => false
method3('foo') # => true
method3(/foo/) # => true
method3('baz') # => false
method3(/baz/) # => false
You have to be careful interpolating a regular expression object into another regular expression:
string = /foo/
/#{string/ # => /(?-mix:foo)/
The (?-mix: are the pattern flags being inserted inside another pattern, which can open your pattern to all sorts of weird behaviors and create extremely hard to find bugs. Instead, I strongly recommend using the source method if you're going to do that, which results in the original pattern being inserted:
/#{string.source}/ # => /foo/
Code with single line:
!#text.match(/#{string}/).nil?

What is the difference between "include?" and "match"?

This is my code:
fred = {
'age' => 63,
'gender' => 'male',
'favorite painters' => ['Monet', 'Constable', 'Da Vinci']
}
fred.delete_if { |k,v| k.match(/[a]/) }
puts fred
The result shows {"gender"=>"male"}.
If I change the code to
fred.delete_if { |k,v| k.include?(/[a]/) }
it won't work.
Can anyone explain why to me?
String#match takes a regex object (or a regex pattern string) as the parameter while String#included? takes a string as the parameter.
You should use:
fred.delete_if { |k,v| k.include?('a') }
For more info, see the document.
.include? returns boolean true/false, and expects a string as input.
.match returns information about the match in the form of MatchData (or nil if nothing was matched), and accepts a string or regular expression.
Everyone is recommending using include? for a literal match. I prefer a different syntax that accomplishes the same thing:
"foo".include?("o") # => true
"foo"["o"] # => "o"
"foo".include?("a") # => false
"foo"["a"] # => nil
In Ruby, anything that is not nil or false is considered true, so, for boolean tests the above tests are equivalent if you get a value or true, or if you get false or nil.
If you absolutely must have a boolean result, use the !! ("not not") trick which nicely converts a "truthy" value to its boolean complement, then back to that value's boolean complement.
true # => true
false # => false
'a' # => "a"
nil # => nil
!true # => false
!false # => true
!'a' # => false
!nil # => true
!!true # => true
!!false # => false
!!'a' # => true
!!nil # => false
Which lets us do:
!!"foo"["o"] # => true
!!"foo"["a"] # => false
This results in more compact code, which might not be what your particular coding-style wants. It pushes the Ruby code toward Perl or C code so weigh the compactness with readability and pick which style you want.
See String#[] for more information.

test(?e, ARGV[0])

What is the test function in the next Ruby expression:
unless ARGV.size == 1 and test(?e, ARGV[0])
test() seems to be reminiscent of the shell tests to see if files or directories exist, are readable, etc:
irb(main):011:0> test(?e,"/etc/passwd") # e for exist
=> true
irb(main):012:0> test(?e,"/does/not/exist")
=> false
irb(main):014:0> test(?e,"/etc")
=> true
irb(main):015:0> test(?d, "/etc") # d for directory
=> true
irb(main):016:0> test(?d, "/etc/passwd")
=> false
irb(main):017:0> test(?r, "/etc/passwd") # r for readable
=> true
irb(main):018:0> test(?w, "/etc/passwd") # w for writable
=> false
Full details are in the ri Kernel#test documentation.

Resources