ruby conditions using && and || - ruby

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'})

Related

Ruby variable not read in loop

Ruby newbie getting even more confused.
If I remove the discountgiven == false from the 4th line, code in the condition works.
If I add it back, the code doesn't work.
What am I doing wrong?
Is it something wrong in the discountgiven variable scope?
discountgiven = false
Input.cart.line_items.each do |item|
product = item.variant.product
if product.tags.include? 'device-ePod' && discountgiven == false
discount_to_apply = item.line_price * (1.0)
item.change_line_price(item.line_price - discount_to_apply, {message: 'Free Epod'})
discountGiven = true
end
end
use parentheses in conditions:
Change :
if product.tags.include? 'device-ePod' && discountgiven == false
to
if product.tags.include?('device-ePod') && discountgiven == false
Your former logic is being evaluated as if product.tags.include?('device-ePod' && discountgiven == false)
Also, what spickermann suggested, you probably typo in discountGiven. It should be discountgiven.

&& 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

Refactoring some Ruby Code

I need some help refactoring some ruby code. Im not keeping it DRY at all.
if potatoes
if item.type != nil
if item.has_stuff == false && (item.something_else).to_f >= (comparing).to_f
# RUN JOB A
else
# RUN JOB B
end
else
# RUN JOB A
end
else
# RUN JOB B
end
I just created random names for things.
if potatoes && (item.type.nil? || (item.has_stuff == false && (item.something_else).to_f >= (comparing).to_f))
# JOB A
else
# JOB B
end
But for such complicated logic, it might be better to pull part of that into a method
def item.has_some_property?(comparing)
has_stuff == false && something_else.to_f >= comparing.to_f
end
if potatoes && (item.type.nil? || item.has_some_property?(comparing))
# JOB A
else
# JOB B
end
if !potatoes
# Job B
elsif item.type.nil?
# Job A
elsif item.has_stuff != false
# Job B
elsif item.something_else.to_f >= comparing.to_f
# Job A
else
# Job B
end
If you associate the jobs to external methods (defined elsewhere) you can keep it dry by using ternary operators, and using a different perspective, considering that the conditions are complementary... to keep the code more readable you can write the conditions on different lines, if you wish, or you should use a method to perform the checks (i.e. item.has_stuff == false && (item.something_else).to_f >= (comparing).to_f) if meaningful in your code...
A quick example:
def is_empty_and_something_less_than_something?(comparing)
item.has_stuff == false && (item.something_else).to_f >= (comparing).to_f
end
job_a_conditions= potatoes && (item.type.nil? || item.is_empty_and_something_less_than_comparing?(comparing))
job_a_conditions ? job_a : job_b
The same conditions can be associated to a method, if re-used in your code.

Test if string is not equal to either of two strings

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) %>

Resources