RSpec should be_true vs should == true - ruby

Is there any difference at all between:
something.should == true
and
something.should be_true
?

The convention is: expect(something).to be_true however there is no difference when used properly. Expecting something to == true should only be evaluated against expressions.
See docs: https://github.com/rspec/rspec-expectations#truthiness
Rspec Tests:
describe "is the equation true? " do
let!(:add) { 5+5 == 10 }
it "be_true" do
add.should be_true #passes
end
it "expect be_true" do
expect(add).to be_true #passes
end
it "== true" do
add.should == true #passes
end
end
Update for strings:
A string is not == true so it will fail, but it will pass as be_true because anything except for false or nil is considered truthy. However, this is NOT how you check for a string.
See this example for how to properly check for a value in a string:
str = "happy dance!"
For finding if text is in a string, you would use: expect(str).to include("happy dance!")

The answer supplied to this question is wrong as the below depicts, the first test is a test of equality while the second is a test of truthiness, the first would fail because something != true while the later would pass because anything order than nil or false is truthy in ruby
require 'rspec'
describe "do something" do
let(:something) { "hey" }
it { something.should == true }
it { something.should be_true }
end

No, there is no difference.
The latter is syntactic sugar for the former.

Related

(ruby) If a conditional variable is nil in an if-else block statement, what will the program print in ruby?

In ruby, let's suppose we have this code:
foo = nil
if foo
puts "foo is true"
else
puts "foo is false"
end
what will this above program print exactly?
Usually, Ruby developers do not care that much if a variable or condition is exactly true or false. Instead Ruby has the concept of truthy and falsey values.
false and nil are falsey, everything else is truthy.
In your example
if foo
puts "foo is true"
else
puts "foo is false"
end
the output would be "foo is false" because nil is falsey and therefore the else block is evaluated.
When running the example in the console then nil would be returned at the end, because nil is returned by the puts method (see docs) and the Ruby console always returns the return value of the last method call.
The answer is that code above will print "foo is false" and also output nil. If someone knows why please comment on this answer or post a new answer to the above question.
So,
if foo
puts "foo is true"
else
puts "foo is false"
end
will print:
foo is false
=> nil
if you are using ruby console
Update: The user "spickermann" explained it perfectly here I think, link

Ruby: Clean code for checking nil /false conditional statement?

I always meet this Ruby problem, I want to write it more cleanly.
var a can be nil
a.value can also be nil
a.value has possible true or false value
if (not a.nil?) && (not a.value.nil?) && a.value == false
puts "a value is not available"
else
puts "a value is true"
end
The problem is that the conditional statement is too clumsy and hard to read.
How can I improve the checking nil and false conditional statement?
Thanks, I am a Ruby newbie
Ruby on rails has an extension called try which allows you to write:
if a.try(:value) == false
which is very clean. Without try, you can just write
if a && a.value == false
If a.value is nil, it is not false, so that is ok :)
If it is possible that a.value is not defined (which would raise an exception), I would write that as follows:
if a && a.respond_to?(:value) && a.value == false
[UPDATE: after ruby 2.3]
Since ruby 2.3 there is an even shorter version:
if a&.value == false
which is almost equivalent to a.try(:value) (but is pure ruby). Differences:
if value does not exist, the &. operator will throw, try will just return nil (preferable or not?)(note: try! would also throw).
when cascading try or &. they also handle false differently. This follows logically from previous difference, try will return nil, while &. will throw because false knows no methods :P
You can achieve it in more compacted way using Safe Navigation Operator (&.):
if a&.value == false
Source : http://mitrev.net/ruby/2015/11/13/the-operator-in-ruby/
if a && a.value!=false
puts "a value is true"
else
puts "a value is not available"
end
or just
puts a && a.value!=false ? "a value is true" : "a value is not available"
The simplest and cleanest way is to flip it and reverse it. Check for the truthy value rather than the falsey values
if a && a.value
puts "a value is true"
else
puts "a value is not available"
end
Of course in Rails you could do it either way by using blank? or present?
Your condition is redundant. If a.value is to be false, then it would not be nil.
if a.nil?.! && a.value == false
puts "a value is not available"
else
puts "a value is true"
end
This will always return a boolean, if nil it will return false; if false it returns false; if true returns true. Try it out, it's nice and short:
!!a.try(:value) == false

Ruby case statement on a hash?

This is going to sound weird, but I would love to do something like this:
case cool_hash
when cool_hash[:target] == "bullseye" then do_something_awesome
when cool_hash[:target] == "2 pointer" then do_something_less_awesome
when cool_hash[:crazy_option] == true then unleash_the_crazy_stuff
else raise "Hell"
end
Ideally, I wouldn't even need to reference the has again since it's what the case statement is about. If I only wanted to use one option then I would "case cool_hash[:that_option]", but I'd like to use any number of options. Also, I know case statements in Ruby only evaluate the first true conditional block, is there a way to override this to evaluate every block that's true unless there is a break?
You could also use a lambda:
case cool_hash
when -> (h) { h[:key] == 'something' }
puts 'something'
else
puts 'something else'
end
Your code is very close to being valid ruby code. Just remove the variable name on the first line, changing it to be:
case
However, there is no way to override the case statement to evaluate multiple blocks. I think what you want is to use if statements. Instead of a break, you use return to jump out of the method.
def do_stuff(cool_hash)
did_stuff = false
if cool_hash[:target] == "bullseye"
do_something_awesome
did_stuff = true
end
if cool_hash[:target] == "2 pointer"
do_something_less_awesome
return # for example
end
if cool_hash[:crazy_option] == true
unleash_the_crazy_stuff
did_stuff = true
end
raise "hell" unless did_stuff
end
I think, following is the better way to do the stuff you want.
def do_awesome_stuff(cool_hash)
case cool_hash[:target]
when "bullseye"
do_something_awesome
when "2 pointer"
do_something_less_awesome
else
if cool_hash[:crazy_option]
unleash_the_crazy_stuff
else
raise "Hell"
end
end
end
Even in case's else part you can use 'case cool_hash[:crazy_option]' instead of 'if' if there are more conditions. I prefer you to use 'if' in this case because there is only one condition.
in ruby 3.0 you can do the following with pattern matching
# assuming you have these methods, ruby 3 syntax
def do_something_awesome = "something awesome 😎"
def do_something_less_awesome = "something LESS awesome"
def unleash_the_crazy_stuff = "UNLEASH the crazy stuff 🤪"
you can do
def do_the_thing(cool_hash)
case cool_hash
in target: "bullseye" then do_something_awesome
in target: "2 pointer" then do_something_less_awesome
in crazy_option: true then unleash_the_crazy_stuff
else raise "Hell"
end
end
will return
do_the_thing(target: "bullseye")
=> "something awesome 😎"
do_the_thing(target: "2 pointer")
=> "something LESS awesome"
do_the_thing(crazy_option: true)
=> "UNLEASH the crazy stuff 🤪"
in ruby 2.7 it still works
# need to define the methods differently
def do_something_awesome; "something awesome 😎"; end
def do_something_less_awesome; "something LESS awesome"; end
def unleash_the_crazy_stuff; "UNLEASH the crazy stuff 🤪"; end
# and when calling the code above to do the switch statement
# you will get the following warning
warning: Pattern matching is experimental, and the behavior may change
in future versions of Ruby!

What happens when you have a case statement with no argument and the when clauses are lambdas?

This code does not perform as I expect:
case
when -> { false } then "why?"
else "This is what I expect"
end
# => "why?"
Neither does this
case
when ->(x) {false} then "why?"
else "This is what I expect"
end
# => "why?"
The first then clause is executed in both cases, which must mean that the lambda I supply to the when clause is not being called. I understand that the case equality operator === should be called on whatever the subject of the when clause is. I am wondering what goes on the other side of the === when there is no argument supplied to case. I was thinking it might be nil, but it can't be:
-> {false} === nil
# => ArgumentError: wrong number of arguments (1 for 0)
->(x) {false} === nil
# => false
This performs as expected and, if it were being executed, would lead to my expected case results or an exception. Can someone explain the results above? It seems that the case equality operator isn't being used at all, and yet the first when clause is evaluating to true. BTW, I am doing this because the output of a case can be used for variable assignment and it is less wordy then having several elsif clauses. I would like to be able to use arbitrary Procs in a case statement with no argument.
case
when -> { false } then puts "why?"
else puts "This is what I expect"
end
case
when 'cat' then puts "why?"
else puts "This is what I expect"
end
case
when -> { false }.call then puts "why?"
else puts "This is what I expect"
end
outputs:
why?
why?
This is what I expect
As The Pickaxe ( http://pragprog.com/book/ruby3/programming-ruby-1-9 ) says, there are two forms of case statement.
The first allows a series of conditions to be evaluated, executing
code corresponding to the first condition that is true: case when ‹
boolean-expression ›+ ‹ then › ...
The second form of a case expression takes a target expression
following the case keyword. case target when ‹ comparison ›+ ‹ then ›
...
In your case (case without target) any expression that is not false or nil (such as a Proc or the string 'cat') evaluates to true. The Proc is not executed, unless you call it.
You can use a case statement without a parameter to act similar to an if statement. For example:
case
when x > 0 then puts "positive"
else puts "negative"
end
You're assuming that it's trying to compare to nil, which isn't the case. Rather, when there's no parameter, the case statement is only testing for a "truthy" value (anything except nil and false). So when it hits your first when statement, it's checking to see if your Proc (meaning the actual ruby Proc object, not the results of executing your Proc) is nil or false, which isn't. Since it's "truthy", that code gets executed.
Try this, and you'll notice the Proc never even gets called/executed (you'll only see "bar", not "foo"):
case
when -> { puts 'foo' } then puts 'bar'
else puts "This line will never be printed"
end

if method_one returns value return value, else try method_two in ruby

How do I say if method_one returns a value, then break, else try method_two?
def ai_second_move(board)
p "2nd move called"
# TODO - how to say if method_one gives me a value, break, else method_two
method_one(board)
method_two(board)
end
Most Ruby way of writing this would be:
method_one(board) || method_two(board)
Ruby executes the right-hand side of || only if the left hand side evaluated to false (meaning it returns nil or false) and then the result of this expression would be that of the method_two
using if -
method_two(board) if method_one(board).nil?
using unless -
method_two(board) unless !method_one(board).nil?
using ternary -
# This evaluates if (method_one(board) returns nil) condition. If its true then next statement is method_two(board) else return is executed next.
method_one(board).nil? ? method_two(board) : return
This would work as well:
method_one(board) and return
The return statement is executed only if method_one(board) returns a truthy value.
You need to use return. break is for loops.
def ai_second_move(board)
p "2nd move called"
return if !!method_one(board)
method_two(board)
end
An other fun way would be
def ai_second_move(board)
p "2nd move called"
!!method_one(board) || method_two(board)
end

Resources