How do you compare multiple RHS values in RSPec? - ruby-on-rails

I'm new to RSpec, and I'm trying to run "should == A || B", but it's ignoring the 'B' and is only comparing with 'A' (and thus failing when val is 'B'):
Sample.find(:all).map(&:param).each{|val| val.should == 'A'||'B'}
Does anyone know how I include the 'B' in the comparison?

['A', 'B'].should include(val)
That might get your spec passing, but is it what you want to test? That the return value is a member of a set? If so, then perhaps this is a good solution.

You can also do:
(x == A || x == B).should be_true

Sample.find(:all).map(&:param).each{ |val| ['A', 'B'].should.include?(value) }
However, this does seem like a bit of an odd test to write.

Assuming you are trying to perform an existence check, I would rewrite your code as follows:
Sample.exists?(:conditions => {:params => %w(A B)}).should_be_true

Related

How to use `or` in RSpec equality matchers (Rails)

I'm trying to do something like
expect(body['classification']).to (be == "Apt") || (be == "House")
Background:
This is testing a JSON API response.
Issue:
I want the test to pass if either "Apt" or "House" are returned. But in the test it is only comparing to the first value, "Apt".
Failure/Error: expect(body['classification']).to be == "Apt" or be == "House"
expected: == "Apt"
got: "House"
Previous Solution:
There is a solution here,
(Equality using OR in RSpec 2) but its depreciated now, and I wasn't able to make it work.
Documentation:
Also wasn't able to find examples like this in the documentation (https://www.relishapp.com/rspec/rspec-expectations/v/3-4/docs/built-in-matchers/equality-matchers)
Is this possible to do?
How about this:
expect(body['classification'].in?(['Apt', 'Hourse']).to be_truthy
Or
expect(body['classification']).to eq('Apt').or eq('Hourse')
Or even this:
expect(body['classification']).to satify { |v| v.in?(['Apt', 'Hourse']) }
expect(body['classification']).to eq("Apt").or eq("House")
Based on this link
"Compound Expectations.
Matchers can be composed using and or or to make compound expectation
Use or to chain expectations"
RSpec.describe StopLight, "#color" do
let(:light) { StopLight.new }
it "is green, yellow or red" do
expect(light.color).to eq("green").or eq("yellow").or eq("red")
end

Construct a dynamic route path in Ruby

I want to construct a dynamic route path in ruby, something like this
route = (a == a) ? "foo" : (b == b) ? "bar" : "default"
link_to(event.try(:name), admin_"#{route}"_path('params goes here')
I very well know what I have tried is wrong. It should be done with dynamic method creations using class_eval or define_method I am not sure about that. Also, I am not familiar with those concepts. I can google but it would take much time to get a solution.
Anyone, please help me solve this quickly. Thanks in advance.
This is pretty straightforward:
send("admin_#{route}_path", params)
You may want to wrap that up in a helper method to clean things up:
def admin_path_for_ab(a, b, params = nil)
route =
if (a == 'a')
"foo"
elsif (b == 'b')
"bar"
else
"default"
end
send("admin_#{route}_path", params)
end
As a note, nesting ternaries (x ? y : z) is usually a bad idea, and a == a is always true.

What is the best way to test if nested list is as expected?

When running a unit test, I'm expecting a method I am testing to return a nested array like this:
[
{:identifier=>"a", :label=>"a label",
:sublist=>[{:identifier=>"sublist z", :label=>"z sublist label"}, {:identifier=>" sublist w", :label=>"sublist w label"}]},
{:identifier=>"b", :label=>"b label",
:sublist=>[{:identifier=>"sublist y", :label=>"y sublist label"}]},
..]
What is the most elegant way to check if the array returned is what I expect it to be?
I'm using Minitest Spec if that makes any difference.
Btw, the order of elements does not matter and may vary.
Thx.
In this case, it would be ideal to write a custom matcher for minitest.
Here, is the code that you would need to add in the matcher.
def match_hash(h1, h2)
matched = false
h1.each do |ele|
h2.each do |ele2|
match_elements?(ele, ele2) ? (matched = true) : next
end
if !matched
return matched
end
end
matched
end
def match_elements?(ele, ele2)
if (ele[:identifier] != ele2[:identifier]) || (ele[:label] != ele2[:label])
return false
end
if ele.has_key?(:sublist) && ele2.has_key?(:sublist)
return match_hash(ele[:sublist], ele2[:sublist])
end
true
end
Write your custom matcher using this example
Then use match_hash in your test case to compare the two hashes.
NOTE: The above code has been tested in irb and it works perfectly.

How to pass a hash as a query with "OR-join"?

I have a hash with booleans
({"u25" => true, "f26t49" => true, "o50" => true, ..});
all in all there are 19 booleans and I want to check these with a table in my db and get those data sets, how have at least one match. I had try it with
"Model.all(:conditions => hash)" or "Model.where(hash)"
but there I get the query
"..u25 == true AND f26t49 == true AND o50 == true..."
but I need something like this:
"..u25 == true OR f26t49 == true..."
I hope you could help me!
ADDITION:
I tryed to make a workaround and generate a query string out of the hash. If i write this string directly (m = Model.where("u25 == 't'")) it works but if I pass a varaible
#query = '"u25 == ' + "'t'" + '"'
m = Model.where(#query)
than m is nil!
I think that your workaround put you in the right direction. Here's what I would do:
# model.rb
def self.search_with_conditions(hash)
query = hash.map{|k,v| "#{k} == #{v}"}.join(' OR ')
where(query)
end
And then in your controller, simply call:
m = Model.search_with_conditions(hash)
Sidenote: This might work for some DBs and not for others as some use 1 as the value for true. Also, I didn't have time to try this so I may be missing some quotation marks in that condition. I think it could be '#{v}'.
EDIT: After learning a little bit more about Rails, I must add a disclaimer here:
If the strings k or v are part of some user input, this approach is susceptible to SQL injection. Use this method with care.

How do write conditional statement in a single line? rails

I am trying to say this
self.preferred_amount * object.each{|li|li.variant}.collect{|li|li.weight}
The only problem is that certain weights equal nil.
Being that the case, I would like to add that if they do equal nil, make them equal 0.
Is there any way to incorporate this logic in the same line?
Or is there a way I can make this statement even more refactored than it is?
Change li.weight to li.weight || 0
|| is the "short circuit or" operator. If its left hand side is truthy (neither false nor nil), it returns the left hand side, otherwise it returns the right hand side.
There is a feature in MRI >= 1.8.7 that will let you make this terser. Instead of:
each{|li|li.variant}
you can write
each(&:variant)
In versions of Ruby before 1.8.7, require the backports gem to get this feature.
Better than that, move all of the logic into object's class, e.g.
class Whatever
def variant_weights
each(&:variant).collect{ |li| li.weight || 0}
end
end
and to use it:
self.preferred_amount * object.variant_weights
However, note that it is a bug to multiply a scalar amount by an array. If you mean to sum the weights, then:
class Whatever
def total_variant_weights
each(&:variant).collect{ |li| li.weight || 0}.inject(&:+)
end
end
and to use it:
self.preferred_amount * object.total_variant_weights
Note, all the answers above are correct for your purpose, but to answer your question directly:
How do I write a conditional statement in a single line? Rails
You can use ternary operators. They take the following form:
assertion ? value_if_true : value_if_false
# if assertion is true, then value_if_true, otherwise, value_if_false
for example:
puts 4 < 5 ? 'you are on Earth' : 'you are on another planet'
<%= #user.is_admin? ? 'you can access this page' : 'you aren\'t allowed to be here' %>
Like I said, the answers above are actually what you want for this particular operation (not that a ternary operator won't work in this case). I just wanted to give you some more insight into one-liners.
Also note, this is not Ruby-specific. Most programming languages (including Ruby, PHP, CF, AS, JAVA, C, C#...) have ternary operators.
just || 0 the weight:
self.preferred_amount * object.each{|li|li.variant}.collect{|li|li.weight || 0}
Try
.collect{|li|li.weight || 0}
The each seems redundant. What about:
self.preferred_amount * object.collect { |o| o.variant.weight.to_i }
or if you really meant to sum the weights:
self.preferred_amount * object.inject { |sum, o| sum + o.variant.weight.to_i }

Resources