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.
Related
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 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 }
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.
So in my rails form there are several rows of 2 textfields. For the form to save ok, at least one of the pair of textfields needs to be filled out.
So
nil nil
10 20
nil nil
nil nil
is valid.
This:
nil nil
nil nil
nil nil
nil nil
is invalid
This:
nil 10
nil nil
nil nil
nil nil
is invalid
Here is the method I am using to check all the fields (note that single_field and aggregate_field are strings and are the field names):
def no_values_present?(single_field, aggregate_field)
self.lo_item.lo_line_items.each do |item|
return false if "!item.#{single_field}".nil? && "!item.#{aggregate_field}".nil?
end
true
end
But I guess this doesn't work as it will return true or false several times and will determine that a row is invalid even though a previous row may have been valid.
I need an overall true or false.
How can this be achieved?
Try leveraging any? or none? from the Enumerable module.
Your code could be rewritten as
def no_values_present?(single_field, aggregate_field)
self.lo_item.lo_line_items.none? { |item|
!(item.send(single_field).nil?) && !(item.send(aggregate_field).nil?)
}
end
although I think that it would be clearer to have the condition be positive and to return true when there is a match found. I would write
def any_pairs_present?(single_field, aggregate_field)
self.lo_item.lo_line_items.any? { |item|
!(item.send(single_field).nil?) && !(item.send(aggregate_field).nil?)
}
end
Note that "!item.#{single_field}" will never be nil because it will always be a string! If you want to access instance fields dynamically then one way to do that is with send, but for other options you could look here which suggests the alternatives of instance_eval and instance_variable_get.
The function looks ok, but there seems to be syntax errors, I'd also make a few amendments:
def form_valid?(single_field, aggregate_field)
self.lo_item.lo_line_items.each do |item|
return true if !item.send(single_field).nil? && !item.send(aggregate_field)
end
false
end
I don't understand the second line of the code below because of "obj = nil" in the first line.Given that, the second line seems to me that "obj" always becomes nil, return false and params[:id].to_i would be put into id_num. Could you tell me why it is written like this?
☆application_controller
def me? obj = nil
id_num = obj !=nil ? obj.member_id : params[:id].to_i
if session[:user_id] == id_num then
return true
else
return false
end
end
Declaring a method that has a parameter set to nil means that the parameter is optional.
def output_object_or_say_duck(obj=nil)
if obj
puts obj
else
puts 'Duck'
end
end
A good example of optional parameters as a design pattern is when you want default behavior that can be customized if necessary. A web request is a good example.
def make_web_request(website, parameters={}) # parameters OR empty hash
Net::HTTP.get("#{website}?#{ parameters.to_query }")
end
This line of code:
id_num = obj !=nil ? obj.member_id : params[:id].to_i
is a ternary operator which says if the object exists, assign id_num to the member_id attribute of obj, otherwise use param[:id].to_i (.to_i converts to an integer).
The obj = nil in the first line simply indicates that the default value of the obj parameter is nil. Meaning that if you don't call the method with any arguments, obj will be set to nil. So the me? method can take 0 or 1 arguments.