rspec what is the difference between be nil and be_nil - ruby-on-rails

I am using rspec and for asserts like
student.name should be nil
student.name should be_nil
Both seem to work. is there a difference between using be nil an be_nil ???

There is no difference really, except be nil gets defined on the fly, and be_nil has been specifically programmed by rspec.
when you say should.be something, rspec tries the following
[:==, :<, :<=, :>=, :>, :===].each do |operator|
define_method operator do |operand|
BeComparedTo.new(operand, operator)
end
end
Whereas, when you try should.be_nil it just checks
object.nil?
https://github.com/rspec/rspec-expectations/blob/master/lib/rspec/matchers/built_in/be.rb

I think there is no difference but it's used for consistency with other methods like be_true or be_false.
Under the hood be checks the id of both elements:
works with nil
fails with true because in Ruby everything not false nor nil is true
fails with false since both nil and false match

Related

rubocop app controller function validate param integer use of nil? predicate

I tried rewriting this function numerous ways to get around this error, however, I want to defer to other experts before I disable the cop around it.
def numeric?(obj)
obj.to_s.match(/\A[+-]?\d+?(\.\d+)?\Z/) == nil ? false : true
end
This is used like so:
def index
if params[:job_id] && numeric?(params[:job_id])
This issue was solved via: Checking if a variable is an integer
Update trying:
def numeric?(string)
!!Kernel.Float(string)
rescue TypeError, ArgumentError
false
end
Reference How do I determine if a string is numeric?
New error:
def numeric?(arg)
!/\A[+-]?\d+\z/.match(arg.to_s).nil?
end
Passes all Rubocop tests from a default configuration. Complete gist with tests at https://gist.github.com/aarontc/d549ee4a82d21d263c9b
The following code snippet does the trick:
def numeric?(arg)
return false if arg.is_a?(Float)
return !Integer(arg).nil? rescue false
end
Returns false for the following: 'a', 12.34, and '12.34'.
Returns true for the following: '1', 1.
You can write the method
def numeric?(obj)
obj.to_s.match(/\A[+-]?\d+?(\.\d+)?\Z/).nil?
end
You really don't need to do nil comparisons and then based on the decision returning true/false. #nil? method does it for you.

What does a bang before a variable do?

I am reading through the RoR guide on testing (http://guides.rubyonrails.org/testing.html)
About 1/5th down the page it says ""To see how a test failure is reported, you can add a failing test to the post_test.rb test case."
test "should not save post without title" do
post = Post.new
assert !post.save
end
I am trying to understand what the use of the bang (!) before post save means.
In an app that I am developing I have a validattion in the model for post
validates :post, presence: true
If I leave the line as it is, the test passes.
If I remove the bang the test fails (because of the validation)
If I move the bang to after the save an exception is raised (because the validation fails
and the bang returns the error message, I think)
So can you help me understand please, what does the bang in front do nd why does it make the test pass?
Question edit / extension: Why is the second test a fail (F) and not an exception (E)
The bang (!) inverts the result of post.save
assert post.save reads assert that the post does save
assert !post.save reads assert that the post doesn't save
Check out the Ruby Logical Operators section at http://www.tutorialspoint.com/ruby/ruby_operators.htm
Edit for extended question:
assert looks for a true result. If the result is true, it returns a pass for that test. If the result is not true, it returns a fail for that test.
Some pseudo code for the asset method,
def assert(result)
if result == true
return 'Pass'
else
return 'Fail'
end
end
assert true
=> 'Pass'
assert false
=> 'Fail'
If there is an exception in the test or code, the test method will rescue the exception and return (E).
Some pseudo code for the test method,
def test(description, &block)
begin
yield
rescue
return 'Exception'
end
end
test 'test description' do
raise 'An error occurred'
end
=> 'Exception'
! is the Logical Not prefix operator - it is not related to variables or methods.
It can be summarized as:
x !x
--------- ---------
nil true
false true
true false
<other> false
(In this case x is the result of evaluating post.save.)

Check if attribute contains 2 letters in RSpec

What is the right way to test if the field contains 2 letter string with RSpec ? I am following an old example that I guess worked in rails 2. It creates new Address instance, sets invalid value on it, and then trigger valid? on that instance and finally checks if the errors report something wrong.
it 'requires state to be of length 2' do
subject = Address.new
subject.state = 'Cal'
should_not be_valid
subject.errors.on(:state).should_not be_nil
end
Now, Rails 3 doesn't have errors.on, so I tried with
subject.errors[:state].should_not be_nil
But the problem here is that errors[:attribute] is empty Array instead of nil.
You can still say
subject.errors[:state].should_not be_empty
Validation errors are now in errors.messages
errors.messages.should be_present

ActiveRecord - check if value is null, 0 or 1

Rails 3.2.2, Ruby 1.9.2
I'm using MySql and there is column "MyColumn" of TINYINT type. I need to show the status of it on a page. So I created a helper method.
module MyControllerHelper
def result(a)
case a
when false then 'false 0'
when true then 'true 1'
when blank? then 'blank or nil'
end
end
end
The bottom line is that it can also be empty or nil. So it doesn't work as I need. It constantly returns either false 0 or true 1 but never blank or nil even if it should do.
What did I do wrong?
A case uses === for comparison so that's equivalent to:
if false === a
'false 0'
elsif true === a
'true 1'
elsif blank? === a
'blank or nil'
else
nil
end
Rails adds a blank? method to Object that looks like this:
def blank?
respond_to?(:empty?) ? empty? : !self
end
so you can call blank? anywhere, even without a specified receiver: there will always be a self and it will always be an Object. Now you should see that when blank?, while syntactically valid, makes no sense at all: it doesn't call a.blank? and see if a true value came back, it simply checks self.blank? === a for whatever self happens to be.
You're probably better off using an explicit if/else for this:
def result(a)
# false.blank? is true so you don't want a.blank? here.
if(a.nil?)
'nil'
elsif(a)
'true 1'
else
'false 0'
end
end

Is there a more rubylike way of doing this helper function

def work_location(application)
if application.contact.work_location.blank? rescue nil
return false
else
return true
end
return false
end
Basically i want to return true or false ....I only want to return true if the work_location is not blank and i need to catch the nil error
Actually this produces a syntax error
syntax error, unexpected modifier_rescue, expecting keyword_then or ';' or '\n'
..._location.blank? rescue nil
def work_location(application)
application.try(:contact).try(:work_location).present?
end
Personally I dislike handling potential nils by doing rescue false because you catch far more than nils: such a rescue rescues all sorts of other errors, for example it will catch NoMethodError, so if you'd typed one of the method names it would squash that error and make it much harder to track down.
Write tests and check both true and false return cases
Shorten code above with:
def work_location(application)
application.contact.work_location.blank? rescue true
end
As far as I can tell, you are creating a helper method here.
I should define a method on application, which you can then use in your views.
The advantage: it is purely object-oriented. An application should know if it has a workplace or not.
Secondly, use try: it will only attempt the given method or block if the receiver is not nil, else it returns nil.
So :
class Application
def has_work_location?
self.contact.try { |c| c.work_location.present? }
end
end
Note that this usage of try only works in rails 3.2, if you are on an older version it does not accept a block. Furthermore nil.present? works and returns falso, so you could write
def has_work_location?
self.contact.try(:work_location).present?
end
Note: because we are adding a method to application, we can safely assume application, so we only need to check that the contact exists anymore.
In your views you can then just write:
<%= #application.contact.workplace if #application.has_work_place? %>
or something similar. Hope this helps.

Resources