geekq / workflow

Ruby finite-state-machine-inspired API for modeling workflow
MIT License
1.75k stars 207 forks source link

Adding Meta to Events? #95

Closed digerata closed 10 years ago

digerata commented 11 years ago

Working with the library for the first time (I like it a lot!), I ran into a need to provide more information about events. For example:

Meta allows me to add info to the state, but both of these items above are at the event level.

I could see a response saying that the role can be checked in the transition event handler. But doing that doesn't help the view that needs to conditionally display the event for a particular role only.

Why not allow :meta to be specified with the event definition? Is there another recommended way to achieve what I need?

gamov commented 11 years ago

you can:

    state :ready, :meta => {:display_name => 'Ready to order'}  do
      event :order, :transitions_to => :ordered
      event :edit, :transitions_to => :composing, meta: {display_name: 'Back to Composing'}
    end

is it what you want?

digerata commented 11 years ago

Yes!

But when I tried to read from it, the meta was blank.

I used instance.current_state.events and did not see any meta available there.

digerata commented 11 years ago

Okay, I found the meta :) I see you have to use:

instance.current_state.events[:event].meta

When creating UI for the different events, this works, but is a bit verbose. Example:

<% @instance.current_state.events.each do |event, str| %>
    <a href="javascript:performEvent('<%= event %>');" class="btn">
        <%= @instance.current_state.events(event).meta[:display_name] %>
    </a>   
<% end %>

Is there a better way?

geekq commented 11 years ago

Looking for less verbose way?

What about assigning to an intermediate variable like

<% possible_events = @instance.current_state.events %>
<% possible_events.each do |event, str| %>
    <a href="javascript:performEvent('<%= event %>');" class="btn">
        <%= possible_events(event).meta[:display_name] %>
    </a>   
<% end %>
digerata commented 11 years ago

Thanks for the tip geek. I'll work within those constraints.

My perspective is: I have the event in the loop, why can't I access other attributes of the event directly? E.g., instead of having access to the symbol and the string of the symbol, (:event => "event") why not make it the object or object hash (:event => event_object)? In this way, you have @instance.current_state[:event].meta or @instance.current_state[:event][:meta]. The resulting code would be:

<% @instance.current_state.events.each do |name, event| %>
    <a href="javascript:performEvent('<%= name %>');" class="btn">
        <%= event.meta[:display_name] %>
    </a>   
<% end %>

I think meta is really powerful and a great idea. In my case, it's not just the display name. I also have roles of who can trigger an event, etc.

geekq commented 11 years ago

instead of having access to the symbol and the string of the symbol, (:event => "event") why not make it the object or object hash

yes, that would be probably a better API. But too late - that change would be not backward compatible - would break people's code.

Could create an additional iterator like event_details.each ... probably someday...

geekq commented 10 years ago

Implementation of #109 now contains a shortcut similar to what you desired. Look at the flat function https://github.com/geekq/workflow/commit/ff471575678bb4e9a7b76246c6ee0cecf8c8a2e7#diff-709316b732f30ee878cb6dabf4ac2482R14 ant it's usage like:

state.events.flat.each do |event|