I have a function which I'm trying to test
##described_class.expects(:foo).with(
1,
2,
<any number>
)
##described_class.bar()
so here my function bar calls foo. Is there a way to set this up where :foo's third parameter can be any number?
From the question title and the code snipped I'm assuming you're using this version of mocha.
If that's the case then you can pass a block to your with and define your expectations in there, see the docs here.
object = mock()
object.expects(:expected_method).with() { |value| value % 4 == 0 }
object.expected_method(16)
# => verify succeeds
object = mock()
object.expects(:expected_method).with() { |value| value % 4 == 0 }
object.expected_method(17)
# => verify fails
The documentation doesn't have an example with more than one parameter as input, but given Ruby's nature I'd assume something like this would work
##described_class.expects(:foo).with { |first, second, third| first == 1 && second == 2 }
Related
I have a code which calls a boolean function.
can_process = done_recently?(load)
Here is how the done_recently function looks.
def done_recently?(load)
time_window = 10000
load['terminatedAt'] && (load['terminatedAt'] > time_window.minutes.ago.utc.iso8601)
end
In my json data, inside
"load": [{ "terminatedAt": null }]
among lots of other data . This json data is converted into a hash before calling these functions.
What will the done_recently? function return(true/false)? I am new to ruby so i am getting a little confused. please help me out.
I have tried replicating in irb but got confused midway because of some errors.
When your input is { "terminatedAt": null } then
def done_recently?(load)
time_window = 10000
load['terminatedAt'] && (load['terminatedAt'] > time_window.minutes.ago.utc.iso8601)
end
will return nil. nil is returned because the first part of load['terminatedAt'] && ... evaluates to nil which is considered falsy and there for the second part after the && will not be evaluated anymore and the nil is returned immediately.
I am quite new to Ruby and could not find an appropriate answer to my questions. Let's say I have hash named
users_hsh = {}.
I am looping through all of my users in the DB and creating the following.
users.each do |user|
users_hsh[user.full_name] = {
completed_activities: some_integer_value,
active_activities: some_integer_value,
future_activities: some_integer_value
}
end
Now, I created a new hash named
total_sum_not_zero_user_hsh = {}.
I want to loop over all of the users in the users_hsh and check for each user if the total sum of completed_activities + active_activities + future_activities does not equal 0 and if this condition holds, I want to add this user to total_sum_not_zero_user_hsh. I have done the following but seems that this does not work.
users_hsh.each do |usr|
if usr.values.sum != 0
total_sum_not_zero_user_hsh[usr] = {
completed_activities: some_integer_value,
active_activities: some_integer_value,
future_activities: some_integer_value
}
end
end
What am I doing wrong? Thanks in advance!
Let's use your example of:
users_hash = {
"Elvin Jafarli" => {
completed_activities: 10,
active_activities: 2,
future_activities: 0
}
}
Think carefully about what your data structure actually is: It's a hash that maps the user name to some user attributes. If you loop through these values, you don't just get a usr, you get back precisely this mapping.
It's helpful to name your variables descriptively:
users_hsh.each do |user_name, user_attributes|
if user_attributes.values.sum != 0
# ...
end
end
With your attempt, you would have seen an error like this: NoMethodError: undefined method 'values' for #<Array:0x00007fe14e22f538>. What happened is that each usr was actually an Array such as:
["Elvin Jafarli", {completed_activities: 10, active_activities: 2, future_activities: 0}]
I've tried reading some tutorials on refactoring and I am struggling with conditionals. I don't want to use a ternary operator but maybe this should be extracted in a method? Or is there a smart way to use map?
detail.stated = if value[:stated].blank?
nil
elsif value[:stated] == "Incomplete"
nil
elsif value[:is_ratio] == "true"
value[:stated] == "true"
else
apply_currency_increment_for_save(value[:stated])
end
If you move this logic into a method, it can be made a lot cleaner thanks to early return (and keyword arguments):
def stated?(stated:, is_ratio: nil, **)
return if stated.blank? || stated == "Incomplete"
return stated == "true" if is_ratio == "true"
apply_currency_increment_for_save(stated)
end
Then...
detail.stated = stated?(value)
stated = value[:stated]
detail.stated = case
when stated.blank? || stated == "Incomplete"
nil
when value[:is_ratio] == "true"
value[:stated] == "true"
else
apply_currency_increment_for_save stated
end
What's happening: when case is used without an expression, it becomes the civilized equivalent of an if ... elsif ... else ... fi.
You can use its result, too, just like with if...end.
Move the code into apply_currency_increment_for_save
and do:
def apply_currency_increment_for_save(value)
return if value.nil? || value == "Incomplete"
return "true" if value == "true"
# rest of the code. Or move into another function if its too complex
end
The logic is encapsulated and it takes 2 lines only
I like #Jordan's suggestion. However, it seems the call is incomplete -- the 'is_ratio' parameter is also selected from value but not supplied.
Just for the sake of argument I'll suggest that you could go one step further and provide a class that is very narrowly focused on evaluating a "stated" value. This might seem extreme but it fits with the notion of single responsibility (the responsibility is evaluating "value" for stated -- while the 'detail' object might be focused on something else and merely makes use of the evaluation).
It'd look something like this:
class StatedEvaluator
attr_reader :value, :is_ratio
def initialize(value = {})
#value = ActiveSupport::StringInquirer.new(value.fetch(:stated, ''))
#is_ratio = ActiveSupport::StringInquirer.new(value.fetch(:is_ratio, ''))
end
def stated
return nil if value.blank? || value.Incomplete?
return value.true? if is_ratio.true?
apply_currency_increment_for_save(value)
end
end
detail.stated = StatedEvaluator.new(value).stated
Note that this makes use of Rails' StringInquirer class.
I have a array which is inside a hash. I want know the result of the student (pass/fail) using the following array. First I have to match them with particular standard and compare their marks with the hash pass and fails. And I want to get the key pass or fail based on their mark. How to achieve this using Ruby?
array = [
{
:standard =>1
:pass=>{:tamil=>30,:eng=>25,:math=>35},
:fail=>{:tamil=>10,:eng=>15,:maths=>20}
},
{
:standard =>2,
:pass=>{:tamil=>40,:eng=>35,:math=>45},
:fail=>{:tamil=>20,:eng=>25,:maths=>30}
}
]
#student is assumed to be defined
standard = array.select {|standard| standard[:standard] == #student.standard}
eng_pass = #student.eng_mark >= standard[:pass][:eng]
eng_fail = #student.eng_mark <= standard[:fail][:eng]
return [eng_pass, eng_fail, whatever_else_you_want]
So on and forth for various topics.
The syntax in reading values from this structure is something like:
array[0][:pass][:eng]
and accordingly you can do the comparison as usual in batch:
for i in 0..#students_array.length
num = # student's score
standard = # something like array[0][:pass][:eng]
if num > standard
# something like 'put "You passed!"'
end
end
I have a function that generates random output (string).
I need to call that function until I get 3 different outputs (strings).
What is the most elegant way to generate array with 3 unique strings by calling the function, with the limit how many times the function can be called if the output is not generated in specified number of attempts?
Here's what I currently have:
output = []
limit_calls = 5
limit_calls.times do |i|
str = generate_output_function
output.push str
break if output.uniq.size > 2
end
Can this be beautified / shortened to 1 line? I'm pretty sure in ruby.. :)
Thanks
Using a set makes it (a bit) easier:
require 'set'
output = Set.new
limit_calls = 5
call_count = 0
while output.size < 3 and call_count < limit_calls
output << generate_output_function
call_count += 1
end
output
or with an array
output = []
limit_calls = 5
while output.size < limit_calls and output.uniq.size < 3
output << generate_output_function
end
output.uniq
UPDATE with the call limit. Seems like the Array version wins! Thanks Iain!
Will also ponder a version using inject.
UPDATE 2 - with inject:
5.times.inject([]) { |a, el| a.uniq.size < 3 ? a << generate_output_function : a }
there is your oneliner. I am not sure I prefer it cause it is a bit hard to follow.....
Froderik's answer missed out the call_limit requirement. What about a function like...
def unique_string_array(call_limit)
output = []
calls = 0
until (output.size == 3 || calls == call_limit) do
(output << generate_output_function).uniq! && calls+=1
end
output
end
It isn't a one-liner but it is readable... with this implementation, you may end up with arrays less than size 3. The most important thing is that you have a test that asserts the behaviour you want! (in order to test this thoroughly you'll have to stub out the call to generate_output_function)