collectiveidea / interactor

Interactor provides a common interface for performing complex user interactions.
MIT License
3.36k stars 212 forks source link

chaining interactors #77

Closed apneadiving closed 9 years ago

apneadiving commented 9 years ago

Hi,

I like interactors, but I'm not a big fan of organizers.

I'd like to code something usable on the fly, this way:

Interactor::Chain.new([ InteractorClass1, InteractorClass2 ]).call!

having a dedicated object like this could be useful to add other methods like:

Interactor::Chain.new([ InteractorClass1, InteractorClass2 ])
  .on_success {|context|  }
  .on_failure {|failure|    } 

What do you think?

apneadiving commented 9 years ago

We could also consider this interface:

Interactor::Chain.new(InteractorClass1)
   .chain { InteractorClass2 }
   .chain { [InteractorClass3, InteractorClass4] }
   .chain { |context|  some_regular_code }
   .on_failure {}

on_success wouldnt be necessary, would just be a chain

ersatzryan commented 9 years ago

@apneadiving thanks for the idea. I think this is do able, but not sure if it is something we have considered in our current workflows.

Do you have an implementation of this already? We would be happy to take a look.

apneadiving commented 9 years ago

My point is to code it, for sure. Do you agree with the suggested api?

laserlemon commented 9 years ago

I have some ideas brewing currently for adding to organizers, giving them the ability to specify per-interactor options:

class DoAllTheThings
  include Interactor::Organizer

  organize DoThingOne, ignore_failure: true
  organize DoThingTwo, async: true
end

There are several reasons for the addition of per-interactor options but my point is that a chainable interface should allow for these same options. Any chainable interface outside of an organizer should still adhere to an organizer's ability, if for no other reason that we can reuse code.

In your example, how would your chain know when to execute?

So far, I'm not sold on the chain interface but I'd like to see where how the API evolves and this issue is a good forum for that. You'd have the best luck being as organizer-y as possible but I can't guarantee that this is something we'll ultimately decide to pursue.

All the same, thank you!! :clap:

apneadiving commented 9 years ago

the api should be

Interactor::Chain.new(context_init)
   .chain { InteractorClass1 }
   .chain { [InteractorClass2, InteractorClass3] }
   .chain { |context|  some_regular_code }
   .on_failure {}

everything would be evaluated on the fly:

I feel like we could be able to keep your options, of course would be a more verbose syntax, but thats already the case in your example were the slim array of classes is now a few lines.

What lead me to chainable stuff is I have Interactors within Interactors: because some of my interactors have a very small scope, I need them in many places.

So ultimately I want to be able to do:

Interactor::Chain.new(context_init)
   .chain do |context|  
      Interactor::Chain.new(context)
        .chain { InteractorClass } #InteractorClass could itself be a chain
   end
   .chain { SomeOtherInteractorClass } # SomeOtherInteractorClass could itself be a chain
   .on_failure {}

Maybe this is a better way to sell you this :) Actually I already coded a first concept (without interactors) https://github.com/apneadiving/waterfall but to me, it makes sense to merge the concept with interactors.

Let me know :)

apneadiving commented 9 years ago

To sum this up, it would be like synchronous promises chains.

apneadiving commented 9 years ago

May I know your final word please? :)

laserlemon commented 9 years ago

@apneadiving We're not sold on the API yet and have talked about this a bit internally but have not come to any conclusions. In fact, I can't give you any guarantee that we'll have clarity for you on this in the immediate future. Please feel free to work on your own implementation of this but please understand that we can't promise inclusion of your implementation until we have more opportunity to discuss. Thank you!

apneadiving commented 9 years ago

ok thanks for letting me know :)