Does #x ||= work like return #x if #x.present? - ruby-on-rails

Is this:
def x?
return #x if #x.present?
#x = #boolean calculation
end
Equivalent to this for boolean values of #x?
def x?
#x ||= #boolean calculation
end

You should not use either option for memoizing boolean values as both will recalculate if #x is false.
present? is a special kind of rails check that equates to !blank? and false.blank? #=> true but even if this was not a boolean check present? and || are not equivalent. For objects that implement empty? blank defers to that so something that is empty? is also blank? and thus is not present?.
"".present? #=> false
"" || true #=> ""
[].present? #=> false
[] || true #=> []
false.present? #=> false
false || true #=> true
#x ||= some_logic equates to #x = #x || some_logic where obviously if #x is false some_logic will fire.
If you just want to see if #x has already been determined to be a value (e.g. not nil) then you could replace this with
def x?
return #x unless #x.nil?
#x = some_logic
end

It depends.
#x ||= value
is equivalent to
#x = #x || value
which assigns value to #x only if #x is falsy. In Ruby, only false and nil are falsy.
Further, #present? is a concept from Rails (see doc).
Note though that depending on the value that you expect to store in #x, it might be equivalent. #present? is simply the negation of #blank? (also a Rails concept). #blank? is defined on Object as follows:
def blank?
respond_to?(:empty?) ? !!empty? : !self
end
Thus, the behavior of the two snippets you posted is guaranteed to be equivalent when #x contains a value that doesn't define its own #present?, #blank?, or #empty? methods.
Now, FalseClass and NilClass both define #blank?:
def blank?
true
end
TrueClass also defines #blank?:
def blank?
false
end
But this is just an optimization as the default implementation from Object would result in the same values.
Therefore, false and nil will return false for #present? and true will return true for #present?.
From this we conclude that, in the specific case of storing boolean values in #x, the behavior of the two snippets is equivalent.

TL;DR: No
Just to add more examples to the answers already above:
def x1?(new_value)
return #x if #x.present?
#x = new_value
end
def x2?(new_value)
#x ||= new_value
end
say #x was a Number:
#x = 123
x1?('new value')
#x
# => 123
#x = 123
x2?('new value')
#x
# => 123
# 123 == 123, so this works for `Number`
but let's say #x was an empty Array:
#x = []
x1?('new value')
#x
# => 'new value'
#x = []
x2?('new value')
#x
# => []
# 'new value' != [], so it doesn't work for empty Array.
^ and there are all other "types" that this doesn't work as well not just empty Array, some of which have already been answered by others here.

Related

How do I find and replace 'nil' values of Ruby hash with "None" or 0?

I'm trying to drill down to each value in an iteration of an array nested hash and replace all nil values with something like 'None' or 0. Please see my code that is clearly not working. I need to fix this before I pass it to my Views in Rails for iteration and rendering:
My controller:
def show
results = Record.get_record(params[:trans_uuid])
if !results.empty?
record = results.map { |res| res.attributes.symbolize_keys }
#record = Record.replace_nil(record) # this calls method in Model
else
flash[:error] = 'No record found'
end
end
My model:
def self.replace_nil(record)
record.each do |r|
r.values == nil ? "None" : r.values
end
end
record looks like this when passed to Model method self.replace_nil(record:
[{:id=>1, :time_inserted=>Wed, 03 Apr 2019 15:41:06 UTC +00:00, :time_modified=>nil, :request_state=>"NY", :trans_uuid=>"fe27813c-561c-11e9-9284-0282b642e944", :sent_to_state=>-1, :completed=>-1, :record_found=>-1, :retry_flag=>-1, :chargeable=>-1, :note=>"", :bridge_resultcode=>"xxxx", :bridge_charges=>-1}]
each won't "persist" the value you're yielding within the block. Try map instead.
def self.replace_nil(record)
record.map do |r|
r.values.nil? ? "None" : r.values
end
end
In fact, there's a method for that; transform_values:
record.transform_values do |value|
value.nil? ? 'None' : value
end
I realized that using Rails you can use just presence and the or operator:
record.transform_values do |value|
value.presence || 'None'
end

Rails/Ruby incorrectly showing variable not defined

In debugging console, while app running (using binding.pry to interrupt it), I can see that my variable Rails.configuration.hardcoded_current_user_key is set:
pry(#<TasksController>)> Rails.configuration.hardcoded_current_user_key
=> "dev"
But it doesn't appear to be defined:
pry(#<TasksController>)> defined?(Rails.configuration.hardcoded_current_user_key)
=> nil
Yet it works fine to store and test its value:
pry(#<TasksController>)> tempVar = Rails.configuration.hardcoded_current_user_key
=> "dev"
pry(#<TasksController>)> defined?(tempVar)
=> "local-variable"
What is going on?
This is because Rails config implements respond_to? but not respond_to_missing?, and defined? only recognizes respond_to_missing?:
class X
def respond_to?(name, include_all = false)
name == :another_secret || super
end
private
def method_missing(name, *args, &block)
case name
when :super_secret
'Bingo!'
when :another_secret
'Nope.'
else
super
end
end
def respond_to_missing?(name, include_all = false)
name == :super_secret || super
end
end
x = X.new
puts x.super_secret # => Bingo!
p defined?(x.super_secret) # => "method"
puts x.another_secret # => Nope.
p defined?(x.another_secret) # => nil
It's recommended to implement respond_to_missing? along with method_missing, I too wonder why Rails did it that way.
You shouldn't be using defined? on anything but the "stub" of that, or in other words, merely this:
defined?(Rails)
Anything beyond that is highly unusual to see, and I'm not even sure it's valid.
defined? is not a method, but a construct that tests if the following thing is defined as a variable, constant or method, among other things. It won't evaluate your code, it will just test it as-is. This means method calls don't happen, and as such, can't be chained.
If you want to test that something is assigned, then you should use this:
Rails.configuration.hardcoded_current_user_key.nil?

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.

How can I test if a variable is defined?

Here is the pseudo-code of what I want to do:
if #current_user is defined then puts #current_user.name
Use the operator defined? then.
x = 10
defined? x # => "local-variable"
defined? y # => nil
#x = 10
defined? #x # => "instance-variable"
!!defined? x # => true
!!defined? y # => false
write your code as below:
puts #current_user.name if !!defined?(#current_user)
Do you really need to know whether the variable is defined or is it enough to know whether it contains a valid User object?
Instance variables will never raise a NameError, even when they are not defined. They just evaluate to nil, so you can just check for that:
puts #current_user.name unless #current_user.nil?
Since your question is tagged ruby-on-rails, I'll assume that you have ActiveSupport loaded anyway, so you can also use the Object#try extension method:
puts #current_user.try(:name)
puts #current_user.name if instance_variable_defined?(:#current_user)

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

Resources