Test if string is not equal to either of two strings - ruby

I am just learning RoR so please bear with me. I am trying to write an if or statement with strings. Here is my code:
<% if controller_name != "sessions" or controller_name != "registrations" %>
I have tried many other ways, using parentheses and || but nothing seems to work. Maybe its because of my JS background...
How can I test if a variable is not equal to string one or string two?

This is a basic logic problem:
(a !=b) || (a != c)
will always be true as long as b != c. Once you remember that in boolean logic
(x || y) == !(!x && !y)
then you can find your way out of the darkness.
(a !=b) || (a != c)
!(!(a!=b) && !(a!=c)) # Convert the || to && using the identity explained above
!(!!(a==b) && !!(a==c)) # Convert (x != y) to !(x == y)
!((a==b) && (a==c)) # Remove the double negations
The only way for (a==b) && (a==c) to be true is for b==c. So since you have given b != c, the if statement will always be false.
Just guessing, but probably you want
<% if controller_name != "sessions" and controller_name != "registrations" %>

<% unless ['sessions', 'registrations'].include?(controller_name) %>
or
<% if ['sessions', 'registrations'].exclude?(controller_name) %>

Related

&& operator not stopping excution with nil

The class below defies my understanding that nil && 'foo' should return nil and not execute 'foo'
no matter what I tried, with or without parenthesis, #user.another_boolean always returns undefined method another_boolean for nil nilclass. I thought if #user is nil it should stop evaluating there and return nil.
class MyClass
def initialize(user, variable = nil)
#user = user
#variable = variable || user.try(:variable)
end
def result
#result ||= !!(#user &&
#variable &&
#variable.a_boolean ||
#user.another_boolean? ||
#user.a_third_boolean? && instance_method_retuning_a_boolean)
end
end
I also tried to look for the documentation of the && operator inside the ruby documentation but could only find a reference to and which shouldn't be the same thing given their precedence difference.
Any help much appreciated.
Ruby version: 2.2.5
Edit:
#user and #variable are rails model
Rails version: 4.2
It is standard practice in software for && to have a higher precedence than ||.
So the following are all logically equivalent:
b && a || c
a && b || c
c || b && a
c || a && b
Now, your code is a little longer:
#user &&
#variable &&
#variable.a_boolean ||
#user.another_boolean? ||
#user.a_third_boolean? && instance_method_retuning_a_boolean
But again we can group the && operators together to show what it's equivalent to:
(#user && #variable && #variable.a_boolean) ||
(#user.another_boolean?) ||
(#user.a_third_boolean? && instance_method_retuning_a_boolean)
Therefore if #user && #variable && #variable.a_boolean == false, then #user.another_boolean? will be evaluated.
I'm not clear what it is you're trying to achieve - so I don't know if the above logic is correct, or how one might "fix" it, but there's your explanation for why the method is being called.
Your expression has a form of:
aaa &&
bbb &&
bbb.foo ||
aaa.bar ||
aaa.baz && something
it may be reformatted as:
aaa && bbb && bbb.foo
||
aaa.bar
||
aaa.baz && something
It's the same, just whitespaces are laid out differently.
As you can see here, not all terms are protected by the initial aaa&&bbb test.
Most probably you meant this:
#result ||= !!( (
#user &&
#variable
)
&&
(
#variable.a_boolean ||
#user.another_boolean? ||
#user.a_third_boolean?
)
&& instance_method_retuning_a_boolean
)
I've added way too many parentheses than needed, but this way you exactly see what's going on.
Hi Yann and welcome to Stackoverflow. Let me give you some examples that may help you understand the reason for your observation.
You correctly stated that:
nil && true
=> nil
but if you chain additional operators without explicitly use brackets then the following happens:
nil && true || true
=> true
This is because the && operator has higher precedence so you could write the same thing like this, and then its clear why the expression does not stop after the first nil:
(nil && true) || true
I found this article pretty helpful: https://womanonrails.com/operator-precedence-ruby.
So for your case if we would put the brackets as it is now we would have the following:
(#user && #variable && #variable.a_boolean) ||
#user.another_boolean? ||
(#user.a_third_boolean? && instance_method_retuning_a_boolean)
This means that even if the first part of the expression results in false, the #user.another_boolean? still gets evaluated.
So what you probably want is putting brackets explicitly:
(#user && #variable) &&
(#variable.a_boolean || #user.another_boolean? || #user.a_third_boolean?) &&
instance_method_retuning_a_boolean
So now you have the first part, which will check if both #user and #variable are not nil. If any of those is nil, the second part will not be evaluated anymore.
Hope this brings some clarity.
You can probably avoid an overly complex boolean expression by adding a guard clause (or two) that separates the prerequisite conditions from the actual result:
def result
return unless #user
return unless #variable
#result ||= #variable.a_boolean ||
#user.another_boolean? ||
#user.a_third_boolean? && instance_method_retuning_a_boolean
end
I'm not sure if this returns the expected result, but you get the idea.

Is there an elegant way to do this in Ruby?

I want an algorithm to set the preferred name correctly. It will be the preference of the user. The user can choose between the social name and the civil name. Only one of those is mandatory, but if it's nil, I want to pick the other one.
if name_preference == SOCIAL_NAME_PREFERENCE && !social_name.nil? || name_preference == CIVIL_NAME_PREFERENCE && civil_name.nil?
social_name
elsif name_preference == CIVIL_NAME_PREFERENCE && !civil_name.nil? || name_preference == SOCIAL_NAME_PREFERENCE && social_name.nil?
civil_name
end
Another way to emphasize the choice of the user.
if name_preference == CIVIL_NAME_PREFERENCE
civil_name || social_name
elsif name_preference == SOCIAL_NAME_PREFERENCE
social_name || civil_name
end
The example uses the Ruby property that nil evaluates to false. Therefore the nil? check can replaced by ||.
Much easier to understand code:
if name_preference == CIVIL_NAME_PREFERENCE
return civil_name.nil? ? social_name : civil_name
elsif name_preference == SOCIAL_NAME_PREFERENCE
return social_name.nil? ? civil_name : social_name
end
I added the return statements for clarity though they are not needed.
case name_preference
when SOCIAL_NAME_PREFERENCE
social_name.nil? ? civil_name : social_name
when CIVIL_NAME_PREFERENCE
civil_name.nil? ? social_name : civil_name
end

ruby conditions using && and ||

I can't figure how to correctly write the rule
I want express the following rule:
If conclusion is 'negative' one of the premises must be negative.
Here's how I tried to write this.
def test4b
if (#conclusion.getQuality == 'negative' && (#major.getQuality != 'negative' || #minor.getQuality != 'negative'))
validity = "invalid (4b) Negative conclusion without a negative premise"
else
validity = "pass"
end
end
But this isn't working. It seems to exclude every syllogism with a negative premise. Again, I only want to exclude syllogisms where which have a negative conclusion without any negative premises.
It should be:
if (#conclusion.getQuality == 'negative' && (#major.getQuality != 'negative' && #minor.getQuality != 'negative'))
Both of #major and #minor are not to be 'negative'.
Your method is to retrun the logical value of !conclusion => (!major || !minor). The negation of this expression would be:
!conclusion && !(!major || !minor) <=> !conclusion && major && major
(DeMorgan's law). This is the condition youa re lloking for, note there are no || here.
Also note that it would be more readable though if you do:
if (#conclusion.getQuality == 'negative' && [#major, #minor].all? {|m| m.getQuality != 'negative'})
or
if (#conclusion.getQuality == 'negative' && ![#major, #minor].any? {|m| m.getQuality == 'negative'})

Using ruby's 'case'/'when' method with || or && operators, etc

I just tried to run some code that looked like this
def get_proj4(srid, type=nil)
type.downcase! if type
case type
when nil || "epsg"
open("http://spatialreference.org/ref/epsg/#{srid}/proj4/").read
when "esri"
open("http://spatialreference.org/ref/esri/#{srid}/proj4/").read
end
end
and it didn't run properly, returning nil every time. wrapping the nil || "epsg" in parentheses didn't work either
It turns out ruby wouldn't allow me to use the || operator in this
Now I assume ruby takes the case/when method and ultimately breaks it down into a group of conditionals looking something like
x = type
if x == (nil || "epsg")
y = ...runs code...
elsif x == "esri"
y = ...
end
x = nil
y
but obviously it does not. What's going on here?
Thanks
The expression is evaluated first so when nil || "espg" is equivalent to when "espg"1 - it will never match nil.
To match either-or, separate the options with a comma:
case type
when nil, "espg" ..
when "esri" ..
Or, alternatively, perhaps normalize the value:
case (type || "espg")
when "espg" ..
when "esri" ..
Or use the other form that resembles an if-else:
case
when type.nil? || type == "espg" ..
when type == "esri" ..
Or some combination of everything :)
1 This is also the same reason why the example if is suspect. It should probably be written like:
if type.nil? || type == "espg"

validates using Proc

If I remove the || statement below this will work. Any ideas why?
I want it to validate only on categories other than "social" and "news"
validates :image, presence: true, if: Proc.new { |a| a.category != "social" || a.category != "news" }
To validate on categories that's not 'social' and not 'news', you will need
validates :image, presence: true, if: Proc.new { |a| a.category != "social" && a.category != "news" }
SeanLi has given you a correct revision, but allow me to supplement it with some deeper logical understanding.
The confusion here would probably be cleared up by a quick study of DeMorgan's Laws. These are the rules for distributing negations (NOTs) over conjunctions (ANDs) and disjunctions (ORs). Using Ruby syntax:
"Neither p nor q" can be written, equivalently, as either !(p || q) or !p && !q.
Meanwhile, "Not both p and q" / "Either not-p or not-q" can be written, equivalently, as either !(p && q) or !p || !q.
However, as their English renderings make clear, the first pair means something different (is logically distinct from) the second pair.
To risk belaboring the obvious, this fact can be applied to your case by recognizing the equivalence of !(p == q) and p != q.

Resources