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
Related
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.
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.
With the code below, the byebug trips:
cspg_instance = #game_instances.find do |instance|
instance_end_time = TimeOperation.new(:+, instance.start_time, instance.duration).result
if (event.end_time > instance.start_time && event.end_time <= instance_end_time && instance.events.first.period == event.period)
byebug
end
end
This returns the correct result: (edit: this WAS returning the correct result and now returns nil)
cspg_instance = #game_instances.find do |instance|
instance_end_time = TimeOperation.new(:+, instance.start_time, instance.duration).result
if (event.end_time > instance.start_time && event.end_time <= instance_end_time && instance.events.first.period == event.period)
ok = true
end
ok
end
Yet, it returns nil, with only the 'if' condition (without the if statement); whereas find_all and select both return a value.
cspg_instance = #game_instances.find do |instance|
instance_end_time = TimeOperation.new(:+, instance.start_time, instance.duration).result
(event.end_time > instance.start_time && event.end_time <= instance_end_time && instance.events.first.period == event.period)
end
I wonder if anyone has any idea what to make of this; perhaps a ruby or installation failure?
There are two different issues:
1) Why the version with byebug doesn't work
This is the important piece from the docs of find: Returns the first for which block is not false.
Now let's have a look at your cases:
# just writing "true" here, with no if statement will deliver a result
If you just write true at the end of the block then that true is returned and therefore find finds this entry.
if (event.end_time > instance.start_time && event.end_time <= instance_end_time && instance.events.first.period == event.period)
ok = true
end
ok
This case is similar: If the if condition is true you assign true to the ok variable. Because you call ok again in the last line of the block the block returns true and find finds this element.
if (event.end_time > instance.start_time && event.end_time <= instance_end_time && instance.events.first.period == event.period)
byebug
end
But this example in your code is different. Here you open bundle if the if condition is true. This makes the bundler call the last method call in the find block. Calling bundler doesn't return true therefore the whole block doesn't return true and find doesn't pick these entry.
The solution is to return true in the last line of the find block. Because you have already the condition in your code, you could use that directly without assigning true to a variable first.
– for example like this:
cspg_instance = #game_instances.find do |instance|
instance_end_time = TimeOperation.new(:+, instance.start_time, instance.duration).result
event.end_time > instance.start_time && event.end_time <= instance_end_time && instance.events.first.period == event.period
end
2) Why does find_all and select work, but find does not?
In the comments, you clarified that #game_instances is actually not an Array, but an ActiveRecord::Relation. ActiveRecord::Relation#find works totally different than the method on an Array. Simplified find on such a relation expects an id of a record and returns that record within the scope given by the relation. Calling to_a on the relation loads all records into memory an allows you to use Array#find.
From a performance point of view it would make sense to translate the condition into a SQL condition and only load the one record that matches from the database instead of loading all records and find the correct one in your application.
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'})
Hi I'm trying to make a blackjack game using Ruby and am trying to make the values of the picture cards all = 10. Is it okay to use the code I use below to accomplish this? (this is all happening in my Card class)
def value
if #number == ("jack" || "queen" || "king")
10
else
#number.to_i
end
end
You can, but not the way you are using it. You either need to use the entire boolean expression in each portion:
if #number == "jack" || #number == "queen" || #number == "king"
or you can make it simpler by checking the contents of an array:
if ["jack", "queen", "king"].include?(#number)
The parens group things that should be evaluated before other things. So, the above says, evaluate:
("jack" || "queen" || "king")
and return the results. Lets try that in irb:
irb(main):004:0> ("jack" || "queen" || "king")
=> "jack"
Since "jack" is truthy there's no need to look at the rest of the list and "jack" is returned.
This will work fine as long as #number is equal to "jack" but not so much for the other values. You want to compare #number against each value until you get a match or exhaust the list. See #PinneyM's answer of
(#number == "jack") || (#number == "queen") ...
That is a valid ruby snippet, but it doesn't do what you think it does: it first evaluates
("jack" || "queen" || "king")
which evaluates to "jack" as that is the first non false/nil value. It then compares #card to this, so your code is equivalent to
def value
if #number == 'jack'
10
else
#number.to_i
end
end
You could compare each in turn (#number == 'jack') || (#number == 'queen') ||..., you could use %w(jack queen king).include?(#number) or you could use a case statement:
def value
case #number
when 'jack', 'queen', 'king'
10
else
#number.to_i
end
end