Module: Flojo

Defined in:
lib/flojo.rb

Class Method Summary collapse

Class Method Details

.included(host) ⇒ Object



2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/flojo.rb', line 2

def Flojo.included(host)
  
	host.class_eval do          
	  attr_writer :wf_current_state 
	  attr_accessor :_wf_current_event_transition_map, :wf_previous_state
	  protected :wf_current_state=, :_set_workflow_state 
     
    def wf_current_state
      wf_current_state = @wf_current_state.nil? ? wf_initial_state : @wf_current_state 
    end    
    
    if respond_to?(:after_initialize)
      after_initialize :flojo_active_record_init
      
      def flojo_active_record_init
        self.wf_state = self.wf_current_state.to_s if self.respond_to?(:wf_state=)
      end 
    end
    
    def wf_initial_state
      st = self.respond_to?(:wf_state) ? (wf_state || self.class.wf_states[0]) : self.class.wf_states[0] 
      st.to_sym
    end
      	  
	  def self.workflow_states(s)
      @workflow_states = s.uniq.compact
      
      s.each do |st|
        raise "Invalid Parameter. State array elements should be symbols" unless Symbol === st
      end
      
   self.synthesize_state_query_methods
    end
   
    def self.wf_states
      @workflow_states
    end                           

    def self.synthesize_state_query_methods
   @workflow_states.each {|st| define_method("wf_#{st}?") { st.eql?(wf_current_state)}}
 end  
   
 def self.valid_states?(*states)
   states.each {|st| return false if (!@workflow_states.include?(st) && (st != :any)) || !(Symbol === st)}                                               
      return true
    end             
	end
    
  host.class_eval("def self.transition(start_state, end_state); raise 'Invalid Transition State' unless self.valid_states?(start_state, end_state); @wf_current_event_transition_map[start_state]=end_state; end")
     
  host.class_eval do
    def self.event(e, &actions)	  
      event_token = "wf_#{e}" 
      map_token = "#{event_token}_transition_map"   

      #setup a transition map class instance variable and corresponding accessors for each event. 
      self.class_eval("@#{map_token}={}") 
      self.class_eval("def self.#{map_token}; return @#{map_token}; end")    
      self.class_eval("def self.wf_current_event_transition_map=(cem); @wf_current_event_transition_map=cem; end" )                                                
      self.class_eval("@wf_current_event_transition_map = @#{map_token}={}")
      self.class_eval("def self.wf_current_event_transition_map; @wf_current_event_transition_map; end" ) 
      self.class_eval("def self.wf_current_event_transition_map=(cem); @wf_current_event_transition_map=cem; end" )
                    
      #instance event_methods  
      self.class_eval("def #{event_token}; self._wf_current_event_transition_map=self.class.#{map_token}; _set_workflow_state \"#{e}\"; end\n")
      self.class_eval("def #{event_token}!; #{event_token}; _wf_after_transition_save!; wf_after_save if self.class.method_defined? :wf_after_save; end\n" )
              
      #Calls transitions in event block
      actions.call
    end
  end

end