This question already has an answer here:
What is the difference between "be_true" and "be true" in RSpec
(1 answer)
Closed 8 years ago.
I know be false will just return true if the expected value is a pure false value, wherease be_falsey will return true if the expected value is either false or nil.
However, I fail to understand when would I use one or the other. I fail to see an example where be_falsey would be more useful than be false.
There are lots of situations in Ruby where you get a nil result and want to treat it like false. For example, suppose we have a method that handles an options hash, and we want the absence of an option to be the same as the option set to false:
def verbose?(opts)
opts[:verbose]
end
opts = { verbose: false }
expect(verbose?(opts)).to be_falsey # => PASS
opts = { verbose: true }
expect(verbose?(opts)).to be_falsey # => FAIL
opts = {}
expect(verbose?(opts)).to be_falsey # => PASS
Obviously this is a simplistic example (you could argue that verbose? should always return true or false), but similar scenarios are common in Ruby.
One example I can think of is for a unit test for a method. The method would be used in such a way that you are not really interested in the result, but only whether it is truthy/falsey.
Consider a method that checks if there is a record with a given value is in the db:
Class Foo
def self.has_value? value
Foo.find(value: value)
end
This method would be used as:
if Foo.has_value?(value)
...
Now, you could write a test like this:
let(:foo ){ create :foo )
expect(Foo.has_value?(1)).to == foo
But this obscures the intent of the method. The method's intent is not to find a foo. It is to tell you whether a foo with a given value exists or not.
To express the intent of the method it might be better to use
expect(Foo.has_value(1).to be_truthy
expect(Foo.has_value(2).to be_falsey
In Rails, if model.save is often used. This is the same pattern.
Related
This question already has answers here:
Why does `defined?` return a string or nil?
(2 answers)
Closed 7 years ago.
In ruby, most methods or keywords that end with ? return boolean values. And we except them to behave like this. Why does defined? keyword return somethings else? Or why is there ? at the end of it?
This question can be understood in two ways:
Why doesn't it simply return true or false?
It's because it encodes more information than simply if something is defined or not:
defined? Class # => "constant"
defined? 42 # => "expression"
defined? nil # => "nil"
defined? x # => nil
Why does it have ? at the end since as the convention goes, the question mark is reserved for predicates?
You are right that this is inconsistent. The most likely reasons are:
Almost always, you will use it as predicate anyway
if defined? x
# do something
end
The shortest alternative, which doesn't sound like a predicate I can think of is definition_type_of. Generally, you want to keep the reserved words in your language short
Developers chose to return something more meaningfull than true or false because the only case that breaks by not having boolean returned is explicit comparison:
defined?(:x) == true
# => always `false`
Such comparison is something you should usually not do, as logical operators like || and && are just as likely to return some truthy object instead of true. This is barely needed for anything.
The "defined?"-method can return more than "true" or "false". It tells you what type of variable it is if it's defined at all.
Check
Checking if a variable is defined?
and
http://ruby-doc.org/docs/keywords/1.9/Object.html#method-i-defined-3F
This question already has answers here:
What does ||= (or-equals) mean in Ruby?
(23 answers)
Closed 8 years ago.
I have some doubts regarding OR EQUALS (||=) operator in ruby. How does ruby interpreter implement it? Here is a sample of code:
class C
def arr
#num ||= []
end
end
When we use OR EQUALS operator in this circumstances, the first call to this method initializes the variable and adds an element, that's fine. When a second call is made to arr, how does it know that array has one element in it..
In Ruby, there are two values that are considered logical false. The first is the boolean value false, the other is nil. Anything which is non-nil and not explicitly false is true. The first time though the method, #num is nil, which is treated as false and the logical or portion of ||= needs to be evaluated and ends up assigning the empty array to #num. Since that's now non-nil, it equates to true. Since true || x is true no matter what x is, in future invocations Ruby short circuits the evaluation and doesn't do the assignment.
In general terms x ||= y is equivalent to x = x || y, it's just shorthand. It's implemented as the expanded form, same as &&=, += or -=.
Most programming languages, Ruby included, will stop executing a logical comparison statement like || on the first true value it encounters and return that. Likewise, it will halt on the first false value when using &&.
In general terms:
false || foo()
This will return false and not evaluate foo().
The pattern is best described as a "lazy initializer", that is the variable is defined only once, but only when it's actually used. This is in contrast to an "eager initializer" that will do it as early as possible, like inside the initialize method.
You'll see other versions of this pattern, like:
def arr
#num ||= begin
stuff = [ ]
# ...
stuff
end
end
This handles cases where the initial value is not as trivial and may need some work to produce. Once again, it's only actually generated when the method is called for the first time.
How does Ruby know on the second pass to not initialize it again? Simple, by that point #num is already defined as something.
As a note, if you're using values like false that would evaluate as non-true, then ||= will trigger every time. The only two logically false values in Ruby are nil and false, so most of the time this isn't an issue.
You'll have to do this the long-form way if you need to handle false as well:
def arr
return #num unless num.nil?
#num = false
end
There was talk of adding an ||=-like operator that would only trigger on nil but I don't think that has been added to Ruby yet.
My method exists_else takes two parameters: base and fallback. If base is nil, it returns fallback. If it's not nil, it returns base. A call to exists_else(true, false) should return true.
If I use a standard looking if-statement, true is returned like I thought it would be:
def exists_else(base, fallback)
unless base.nil?
base
else
fallback
end
end
a = true
exists_else( a, false )
# => true
If I use the inline implementation shown below, it returns false.
def exists_else(base, fallback)
base unless base.nil? else fallback
end
a = true
exists_else( a, false )
# => false
Why does does it return false in the inline implementation?
Your assertion that
base unless base.nil? else fallback
is supposed to be equivalent to the long-form unless statement is not true; in fact, you cannot use else inside a post condition. Ruby is interpreting the code as:
def exists_else(base, fallback)
base unless base.nil?
else fallback
end
If you type this (or the version without the newline, as in your question) into IRB, Ruby gives the following warning:
warning: else without rescue is useless
That is to say, Ruby is trying to interpret the else as part of exception handling code, as in
def exists_else(base, fallback)
base unless base.nil
rescue ArgumentError => e
# code to handle ArgumentError here
else
# code to handle other exceptions here
end
You can not use an else statement when you're trying to do it in one line. When an else is necessary you must use the extended version.
Ruby thinks that the else in this case is related to error handling. You have to stick to your initial unless-end method.
I prefer this syntax to evaluate true/false checks:
condition(s) ? true_value : false_value
In your case, it would look like:
def exists_else(base, fallback)
base.nil? ? fallback : base
end
a = true
puts exists_else(a, false) # => true
Is there a simple way in Ruby to get a true/false value from something without explicitly evaluating it to true or false
e.g. how would one more succinctly express
class User
def completed_initialization?
initialization_completed == 1 ? true : false
end
end
is there some way to do something along the lines of
initialization_completed.true?
There's obviously not much in it but since I'm in the zen garden of Ruby I might as well embrace it
EDIT (I've updated the example)
This question was extremely badly phrased as was very gently pointed out by #Sergio Tulentsev. The original example (below) does of course evaluate directly to a boolean. I'm still struggling to find an example of what I mean however Sergio's double-negative was in fact exactly what I was looking for.
Original example
class User
def top_responder
responses.count > 10 ? true : false
end
end
> operator already returns boolean value. So it can be just
def top_responder
responses.count > 10
end
To convert arbitrary values to booleans, I offer you this little double-negation trick.
t = 'foo'
!!t # => true
t = 1
!!t # => true
t = 0
!!t # => true
t = nil
!!t # => false
The first negation "casts" value to boolean and inverts it. That is, it will return true for nil / false and false for everything else. We need another negation to make it produce "normal" values.
Just wondering what !! is in Ruby.
Not not.
It's used to convert a value to a boolean:
!!nil #=> false
!!"abc" #=> true
!!false #=> false
It's usually not necessary to use though since the only false values to Ruby are nil and false, so it's usually best to let that convention stand.
Think of it as
!(!some_val)
One thing that is it used for legitimately is preventing a huge chunk of data from being returned. For example you probably don't want to return 3MB of image data in your has_image? method, or you may not want to return your entire user object in the logged_in? method. Using !! converts these objects to a simple true/false.
It returns true if the object on the right is not nil and not false, false if it is nil or false
def logged_in?
!!#current_user
end
! means negate boolean state, two !s is nothing special, other than a double negation.
!true == false
# => true
It is commonly used to force a method to return a boolean. It will detect any kind of truthiness, such as string, integers and what not, and turn it into a boolean.
!"wtf"
# => false
!!"wtf"
# => true
A more real use case:
def title
"I return a string."
end
def title_exists?
!!title
end
This is useful when you want to make sure that a boolean is returned. IMHO it's kind of pointless, though, seeing that both if 'some string' and if true is the exact same flow, but some people find it useful to explicitly return a boolean.
Note that this idiom exists in other programming languages as well. C didn't have an intrinsic bool type, so all booleans were typed as int instead, with canonical values of 0 or 1. Takes this example (parentheses added for clarity):
!(1234) == 0
!(0) == 1
!(!(1234)) == 1
The "not-not" syntax converts any non-zero integer to 1, the canonical boolean true value.
In general, though, I find it much better to put in a reasonable comparison than to use this uncommon idiom:
int x = 1234;
if (!!x); // wtf mate
if (x != 0); // obvious
It's useful if you need to do an exclusive or. Copying from Matt Van Horn's answer with slight modifications:
1 ^ true
TypeError: can't convert true into Integer
!!1 ^ !!true
=> false
I used it to ensure two variables were either both nil, or both not nil.
raise "Inconsistency" if !!a ^ !!b
It is "double-negative", but the practice is being discouraged. If you're using rubocop, you'll see it complain on such code with a Style/DoubleNegation violation.
The rationale states:
As this is both cryptic and usually redundant, it should be avoided
[then paraphrasing:] Change !!something to !something.nil?
Understanding how it works can be useful if you need to convert, say, an enumeration into a boolean. I have code that does exactly that, using the classy_enum gem:
class LinkStatus < ClassyEnum::Base
def !
return true
end
end
class LinkStatus::No < LinkStatus
end
class LinkStatus::Claimed < LinkStatus
def !
return false
end
end
class LinkStatus::Confirmed < LinkStatus
def !
return false
end
end
class LinkStatus::Denied < LinkStatus
end
Then in service code I have, for example:
raise Application::Error unless !!object.link_status # => raises exception for "No" and "Denied" states.
Effectively the bangbang operator has become what I might otherwise have written as a method called to_bool.
Other answers have discussed what !! does and whether it is good practice or not.
However, none of the answers give the "standard Ruby way" of casting a value into a boolean.
true & variable
TrueClass, the class of the Ruby value true, implements a method &, which is documented as follows:
Returns false if obj is nil or false, true otherwise.
Why use a dirty double-negation when the standard library has you covered?