views:

20

answers:

1

I currently have the following code:

events.detect do |event|

#detect does the block until the statement goes false

  self.event_status(event) == "no status"

end

What this does is output the instance of event (where events is a string of different Models that all collectively call Events) when the event_status method outputs a "no status".

I would like the output to also include the value for delay where:

delay = delay + contact.event_delay(event)

event_delay method hasn't been written, but it would be similar (maybe redundant but I'll deal with that later) to event_status in looking at the delay between when an event was done and when it was supposed to be done.

Here is how event_status looks currently for reference:

  def event_status target
  # check Ticket #78 for source

    target_class= target.class.name
    target_id   = target_class.foreign_key.to_sym

    assoc_name  = "contact_#{target_class.tableize}"

    r = send(assoc_name).send("find_by_#{target_id}", target.id) 
    return "no status" unless r
    "sent (#{r.date_sent.to_s(:long)})" 
  end

My concept of output should be [event,delay] so that, for example, I can access it as Array[:event] or Array[:delay] to get at the value.

**I was thinking maybe I should use yield on a method, but haven't quite put the pieces together (should the block passed to the method be the delay =+ for example, I think it is).

I am not wed to the .detect method, it's what I started with and it appears to work, but it isn't allowing me to run the tally alongside it.

A: 

It's not entirely clear what you're asking for, but it sounds like you're trying to add up a delay until you reach a certain condition, and return the record that triggered the condition at the same time.

You might approach that using Enumerable#detect like you have, but by keeping a tally on the side:

def next_event_info
  next_event = nil
  delay = 0

  events.detect do |event|
    case (self.event_status(event))
    when "no status"
      true
    else
      delay += contact.event_delay(event)
      false
    end
  end

  [ next_event, delay ]
end

Update for if you want to add up all delays for all events, but also find the first event with the status of "no status":

def next_event_info
  next_event = nil
  delay = 0.0

  events.each do |event|
    case (self.event_status(event))
    when "no status"
      # Only assign to next_event if it has not been previously
      # assigned in this method call.
      next_event ||= event
    end

    # Tally up the delays for all events, converting to floating
    # point to ensure they're not native DB number types.
    delay += contact.event_delay(event).to_f
  end

  {
    :event => next_event,
    :delay => delay
  }
end

This will give you a Hash in return that you can interrogate as info[:event] or info[:delay]. Keep in mind to not abuse this method, for example:

# Each of these makes a method call, which is somewhat expensive
next_event = next_event_info[:event]
delay_to_event = next_event_info[:delay]

This will make two calls to this method, both of which will iterate over all the records and do the calculations. If you need to use it this way, you might as well make a special purpose function for each operation, or cache the result in a variable and use that:

# Make the method call once, save the results
event_info = next_event_info

# Use these results as required
next_event = event_info[:event]
delay_to_event = event_info[:delay]
tadman
Hi, you got the goal right! But I'm not clear how next_event value gets assigned...should it just be event since .detect pulls it out of the block?
Angela
Hi, I added before the second to last end next_event = event assuming that it exists the do loop because of detect.However, when I .inspect the contact.next_event_info I get:[#, Rational(0, 1)]
Angela
It does not appear to loop, when it goes to the else loop, it ends, rather than continuing through all the events.
Angela
`Enumerable#detect` is used to loop up until the point where the block returns a non-true value. Are you looking to add up all delays for all events, but only return the first event with `"no status"`?
tadman
hi, yes, that's what i wanted to do, to make the call once and save the results, I just didn't know how to do that...let me check this out, thanks!
Angela
Hi, I get a funky error: undefined method `-@' for Sun, 08 Aug 2010:DateWhat does that mean -@?
Angela
oh that's an error in my code...hmm, need to figure out how to calculate the delay -- was working before...need to find the difference between two dates...
Angela
Might be best to put that up as a separate question if you need to.
tadman