def register_participant(regex, participant=nil, opts={}, &block)

      if participant.is_a?(Hash)
        opts = participant
        participant = nil
      end

      pa = @context.plist.register(regex, participant, opts, block)

      @context.storage.put_msg(
        'participant_registered',
        'regex' => regex.is_a?(Regexp) ? regex.inspect : regex.to_s)

      pa
    end
def register_participant(regex, participant=nil, opts={}, &block)

      if participant.is_a?(Hash)
        opts = participant
        participant = nil
      end

      pa = @context.plist.register(regex, participant, opts, block)

      @context.storage.put_msg(
        'participant_registered',
        'regex' => regex.is_a?(Regexp) ? regex.inspect : regex.to_s)

      pa
    end
Registers a participant in the engine.

 Takes the form

   dashboard.register_participant name_or_regex, klass, opts={}

 With the form

   dashboard.register_participant name_or_regex do |workitem|
     # ...
   end

 A BlockParticipant is automatically created.


 == name or regex

 When registering participants, strings or regexes are accepted. Behind
 the scenes, a regex is kept.

 Passing a string like "alain" will get ruote to automatically turn it
 into the following regex : /^alain$/.

 For finer control over this, pass a regex directly

   dashboard.register_participant /^user-/, MyParticipant
     # will match all workitems whose participant name starts with "user-"


 == some examples

   dashboard.register_participant 'compute_sum' do |wi|
     wi.fields['sum'] = wi.fields['articles'].inject(0) do |s, (c, v)|
       s + c * v # sum + count * value
     end
     # a block participant implicitely replies to the engine immediately
   end

   class MyParticipant
     def initialize(opts)
       @name = opts['name']
     end
     def on_workitem
       workitem.fields['rocket_name'] = @name
       send_to_the_moon(workitem)
     end
     def on_cancel
       # do nothing
     end
   end

   dashboard.register_participant(
     /^moon-.+/, MyParticipant, 'name' => 'Saturn-V')

   # computing the total for a invoice being passed in the workitem.
   
   class TotalParticipant
     include Ruote::LocalParticipant

     def on_workitem
       workitem['total'] = workitem.fields['items'].inject(0.0) { |t, item|
         t + item['count'] * PricingService.lookup(item['id'])
       }
       reply
     end

     def on_cancel
     end
   end
   dashboard.register_participant 'total', TotalParticipant

 Remember that the options (the hash that follows the class name), must be
 serializable via JSON.


 == require_path and load_path

 It's OK to register a participant by passing its full classname as a
 String.

   dashboard.register_participant(
     'auditor', 'AuditParticipant', 'require_path' => 'part/audit.rb')
   dashboard.register_participant(
     'auto_decision', 'DecParticipant', 'load_path' => 'part/dec.rb')

 Note the option load_path / require_path that point to the ruby file
 containing the participant implementation. 'require' will load and eval
 the ruby code only once, 'load' each time.


 == :override => false

 By default, when registering a participant, if this results in a regex
 that is already used, the previously registered participant gets
 unregistered.

   dashboard.register_participant 'alpha', AaParticipant
   dashboard.register_participant 'alpha', BbParticipant, :override => false

 This can be useful when the #accept? method of participants are in use.

 Note that using the #register(&block) method, :override => false is
 automatically enforced.

   dashboard.register do
     alpha AaParticipant
     alpha BbParticipant
   end


 == :position / :pos => 'last' / 'first' / 'before' / 'after' / 'over'

 One can specify the position where the participant should be inserted
 in the participant list.

   dashboard.register_participant 'auditor', AuditParticipant, :pos => 'last'

 * last : it's the default, places the participant at the end of the list
 * first : top of the list
 * before : implies :override => false, places before the existing
   participant with the same regex
 * after : implies :override => false, places after the last existing
   participant with the same regex
 * over : overrides in the same position (while the regular, default
   overide removes and then places the new participant at the end of
   the list)