flowchart 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +19 -0
- data/README.rdoc +158 -0
- data/flowchart.gemspec +13 -0
- data/lib/flow_chart.rb +71 -0
- data/lib/flowchart/flow_processor.rb +164 -0
- data/sample/sample_one.rb +59 -0
- metadata +72 -0
data/LICENSE.txt
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2013 Shuddhashil Ray(rayshuddhashil@gmail.com)
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
= FlowChart
|
2
|
+
|
3
|
+
- Flowchart is a rubygem for State Machine(state-action-transition) workflow.
|
4
|
+
- Flowchart works out of the box both for ActiveRecord and Non-ActiveRecord Models.
|
5
|
+
- It provides an easy DSL to create a state machine flow for your model's object.
|
6
|
+
|
7
|
+
== INSTALLATION
|
8
|
+
|
9
|
+
gem install flowchart
|
10
|
+
|
11
|
+
# No other gem dependencies! Tested on Ruby 1.8.7 and Ruby 1.9.3
|
12
|
+
|
13
|
+
== SYNTAX & OPTIONS
|
14
|
+
|
15
|
+
flowchart do
|
16
|
+
init_flowstate :init
|
17
|
+
|
18
|
+
flowstate :init do
|
19
|
+
preprocess Proc.new { |o| p "blah blah" }
|
20
|
+
postprocess :some_method
|
21
|
+
end
|
22
|
+
|
23
|
+
flowstate :uploaded do
|
24
|
+
preprocess Proc.new :do_something
|
25
|
+
postprocess Proc.new { |o| p "File has been uploaded" }
|
26
|
+
end
|
27
|
+
|
28
|
+
action :upload do
|
29
|
+
transitions :from => :init, :to => :uploaded, :condition => :file_parsable?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# OPTIONS
|
34
|
+
1. By Default flowchart assumes that the model attribute it works on is "process_status. If you want to override it then :
|
35
|
+
flowchart do
|
36
|
+
state_column :some_other_column
|
37
|
+
.....
|
38
|
+
end
|
39
|
+
|
40
|
+
2. Every flowstate can have options preprocess and postprocess blocks. You can mention any instance methods or Procs/lamdas to execute.
|
41
|
+
|
42
|
+
3. In Actions you can mention :condition with evaluate truth or falsity based on which the transition action(:from -> :to) is possible or not is determined. If :condition is not given transition is always evaluated to truth.
|
43
|
+
|
44
|
+
4. In Actions you can also mention :branch, when you have multiple :to states from one single :from state then you can mention a ":branch" condition which you can execute and determine which branch state will be the next! Useful in decision trees.
|
45
|
+
|
46
|
+
# Methods
|
47
|
+
|
48
|
+
1. obj.{state_name}? returns boolean true/false if object is in that that state
|
49
|
+
|
50
|
+
2. obj.{action} returns the transtion to next state on executing the action
|
51
|
+
|
52
|
+
3. obj.{action}! returns the transition to next state on executing the action and save after call
|
53
|
+
|
54
|
+
4. obj.current_state returns the current_state of the object
|
55
|
+
|
56
|
+
5. obj.flowprocessor returns the complete tree of flowchart for the object!
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
== Sample Use
|
61
|
+
|
62
|
+
# Example of a Non-ActiveRecord Class using FlowChart in Ruby
|
63
|
+
# in irb console
|
64
|
+
|
65
|
+
class SampleOne
|
66
|
+
include FlowChart
|
67
|
+
attr_accessor :process_status
|
68
|
+
|
69
|
+
flowchart do
|
70
|
+
init_flowstate :init
|
71
|
+
|
72
|
+
flowstate :init do
|
73
|
+
preprocess Proc.new { |o| p "Initializing File" }
|
74
|
+
postprocess :notify_user
|
75
|
+
end
|
76
|
+
|
77
|
+
flowstate :uploaded do
|
78
|
+
preprocess Proc.new { |o| p "Validating File" }
|
79
|
+
postprocess Proc.new { |o| p "File has been uploaded in system" }
|
80
|
+
end
|
81
|
+
|
82
|
+
flowstate :open do
|
83
|
+
postprocess :notify_user
|
84
|
+
postprocess Proc.new { |o| p "File has been closed" }
|
85
|
+
end
|
86
|
+
|
87
|
+
flowstate :closed do
|
88
|
+
preprocess Proc.new { |o| p "File closed" }
|
89
|
+
postprocess :notify_user
|
90
|
+
end
|
91
|
+
|
92
|
+
action :upload do
|
93
|
+
transitions :from => :init, :to => :uploaded, :condition => :file_parsable?
|
94
|
+
end
|
95
|
+
|
96
|
+
action :process do
|
97
|
+
transitions :from => :uploaded, :to => [:open, :closed], :branch => :choose_branch
|
98
|
+
end
|
99
|
+
|
100
|
+
action :close do
|
101
|
+
transitions :from => [:init,:uploaded,:open], :to => :closed, :condition => :file_close?
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
def choose_branch
|
107
|
+
6 > 5 ? :open : :closed
|
108
|
+
end
|
109
|
+
|
110
|
+
def notify_user
|
111
|
+
p "Notifying User!"
|
112
|
+
end
|
113
|
+
|
114
|
+
def file_parsable?
|
115
|
+
3 > 2 ? true : false
|
116
|
+
end
|
117
|
+
|
118
|
+
def file_close?
|
119
|
+
1 > 0 ? true : false
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
t=SampleOne.new
|
124
|
+
#<SampleOne:0x9a3d500>
|
125
|
+
|
126
|
+
t.current_state
|
127
|
+
#<FlowChart::State:0x9a3ff1c @flowstatename=:init, @before_and_after_works={:preprocess=>#<Proc:0x09a41880@(irb):11>, :postprocess=>:notify_user}>
|
128
|
+
|
129
|
+
t.upload
|
130
|
+
"Notifying User!"
|
131
|
+
"Validating File"
|
132
|
+
true
|
133
|
+
|
134
|
+
t.current_state
|
135
|
+
#<FlowChart::State:0x9a3fe18 @flowstatename=:uploaded, @before_and_after_works={:preprocess=>#<Proc:0x09a415ec@(irb):16>, :postprocess=>#<Proc:0x09a414c0@(irb):17>}>
|
136
|
+
|
137
|
+
t.process
|
138
|
+
"File has been uploaded in system"
|
139
|
+
|
140
|
+
t.current_state
|
141
|
+
#<FlowChart::State:0x9a3fd00 @flowstatename=:open, @before_and_after_works={:postprocess=>#<Proc:0x09a41240@(irb):22>}>
|
142
|
+
|
143
|
+
t.closed?
|
144
|
+
false
|
145
|
+
|
146
|
+
t.open?
|
147
|
+
true
|
148
|
+
|
149
|
+
t.close
|
150
|
+
"File closed"
|
151
|
+
true
|
152
|
+
|
153
|
+
t.current_state
|
154
|
+
#<FlowChart::State:0x9a3fbfc @flowstatename=:closed, @before_and_after_works={:preprocess=>#<Proc:0x09a41024@(irb):26>, :postprocess=>:notify_user}>
|
155
|
+
|
156
|
+
== Save! in ActiveRecord Model
|
157
|
+
|
158
|
+
For any action if you choose to follow it up with a '!' then the model object is saved after action call. Similarly for an action if you choose to not follow it up with a '!' it will only update the attributes for the model object
|
data/flowchart.gemspec
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Gem::Specification.new do |f|
|
2
|
+
f.name = 'flowchart'
|
3
|
+
f.version = '0.0.1'
|
4
|
+
f.date = %q{2013-09-27}
|
5
|
+
f.summary = %q{State Machine and State Flow for Ruby}
|
6
|
+
f.description = %q{Flowchart is a State Machine(state-action-transition) workflow for Non-ActiveRecord and ActiveRecord Model in Ruby or Rails}
|
7
|
+
f.authors = %q{Shuddhashil Ray}
|
8
|
+
f.email = %q{rayshuddhashil@gmail.com}
|
9
|
+
f.files = ["README.rdoc","LICENSE.txt","flowchart.gemspec","lib/flow_chart.rb","lib/flowchart/flow_processor.rb","sample/sample_one.rb"]
|
10
|
+
f.require_paths = ["lib"]
|
11
|
+
f.homepage = %q{http://github.com/raycoding/flowchart}
|
12
|
+
f.license = "MIT"
|
13
|
+
end
|
data/lib/flow_chart.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'flowchart/flow_processor'
|
2
|
+
module FlowChart
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
base.send :include, InstanceMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
attr_reader :flowprocessor
|
10
|
+
|
11
|
+
def flowchart(&block)
|
12
|
+
@flowprocessor = FlowChart::FlowProcessor.new(&block)
|
13
|
+
@flowprocessor.flowstates.values.each do |flowstate|
|
14
|
+
flowstate_name = flowstate.flowstatename
|
15
|
+
# Helper Methods to verify is this is the current_state, example object.uploaded? , object.closed? etc
|
16
|
+
define_method "#{flowstate_name}?" do
|
17
|
+
flowstate_name == current_state.flowstatename
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
#Driver Instance Methods for each evet for triggering the action action!
|
22
|
+
@flowprocessor.actions.keys.each do |key|
|
23
|
+
define_method "#{key}" do
|
24
|
+
process_action(key,:save_object=>false)
|
25
|
+
end
|
26
|
+
|
27
|
+
define_method "#{key}!" do
|
28
|
+
process_action(key,:save_object=>true)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module InstanceMethods
|
35
|
+
attr_accessor :previous_state
|
36
|
+
|
37
|
+
def flowprocessor
|
38
|
+
self.class.flowprocessor
|
39
|
+
end
|
40
|
+
|
41
|
+
def current_state
|
42
|
+
if (flowprocessor.state_column.to_sym.nil? or send(flowprocessor.state_column.to_sym).nil? or send(flowprocessor.state_column.to_sym)=="")
|
43
|
+
@current_state ||= flowprocessor.flowstates[flowprocessor.starting_flowstate.flowstatename]
|
44
|
+
else
|
45
|
+
@current_state ||= flowprocessor.flowstates[send(flowprocessor.state_column.to_sym).to_sym]
|
46
|
+
end
|
47
|
+
@current_state
|
48
|
+
end
|
49
|
+
|
50
|
+
def set_current_state(new_state, options = {})
|
51
|
+
send("#{flowprocessor.state_column}=".to_sym, new_state.flowstatename.to_s)
|
52
|
+
@current_state = new_state
|
53
|
+
send("#{flowprocessor.state_column.to_s}=".to_sym,"#{current_state.flowstatename.to_s.to_s}") #Updates the instance variable
|
54
|
+
# If asked to save action with bang! and if inherits from ActiveRecord in Rails then do save!
|
55
|
+
## Important check to support both Non-ActiveRecord Models in Ruby and ActiveRecord Models in Rails
|
56
|
+
if options[:save_object] and !(defined?(ActiveRecord::Base).nil?) and self.class.ancestors.include? ActiveRecord::Base
|
57
|
+
self.save
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
def process_action(action_name,options_for_action = {})
|
63
|
+
action = flowprocessor.actions[action_name.to_sym]
|
64
|
+
if action.nil?
|
65
|
+
p "Error: #{action_name} not found!"
|
66
|
+
raise FlowChart::InvalidState.new("Error: #{action_name} not found!")
|
67
|
+
end
|
68
|
+
action.process_action!(self,current_state,options_for_action)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
module FlowChart
|
2
|
+
class InvalidTransition < NoMethodError; end
|
3
|
+
class InvalidState < NoMethodError; end
|
4
|
+
class InvalidAction < NoMethodError; end
|
5
|
+
|
6
|
+
# Driver for States in FlowChart
|
7
|
+
class State
|
8
|
+
attr_accessor :flowstatename, :before_and_after_works
|
9
|
+
|
10
|
+
def initialize(flowstatename, &flowblock)
|
11
|
+
@flowstatename,@before_and_after_works = flowstatename,Hash.new
|
12
|
+
instance_eval(&flowblock) if block_given?
|
13
|
+
end
|
14
|
+
|
15
|
+
## Optional in State flow
|
16
|
+
##Preprocess Things-To-Do before entering this state => Usecase Notifications
|
17
|
+
## Takes a proc or instance method as block
|
18
|
+
def preprocess(method = nil, &block)
|
19
|
+
@before_and_after_works[:preprocess] = method.nil? ? block : method
|
20
|
+
end
|
21
|
+
|
22
|
+
## Optional in State flow
|
23
|
+
#PostProcess Things-To-Do before entering this state => Usecase Notifications
|
24
|
+
## Takes a proc or instance method as block
|
25
|
+
def postprocess(method = nil, &block)
|
26
|
+
@before_and_after_works[:postprocess] = method.nil? ? block : method
|
27
|
+
end
|
28
|
+
|
29
|
+
##Defines how the flow for a State executes with preprocess and postprocess
|
30
|
+
def process_flow(action,base)
|
31
|
+
action = @before_and_after_works[action.to_sym]
|
32
|
+
case action
|
33
|
+
when Symbol, String
|
34
|
+
base.send(action)
|
35
|
+
when Proc
|
36
|
+
action.call(base)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Driver for Transition in FlowChart
|
42
|
+
class Transition
|
43
|
+
attr_reader :condition #boolean condition to verify if transition can be done!
|
44
|
+
attr_reader :branch #selection from multiple branch transition based on condition!
|
45
|
+
attr_reader :from #transit from!
|
46
|
+
attr_reader :to #transit to!
|
47
|
+
|
48
|
+
def initialize(options)
|
49
|
+
@condition = options[:condition]
|
50
|
+
@branch = options[:branch]
|
51
|
+
@from = [options[:from]].flatten
|
52
|
+
@to = options[:to]
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_me_next_state(base)
|
56
|
+
raise InvalidTransition.new("You cannot transit from multiple states without a decision condition!") if @to.is_a?(Array) && @branch.nil?
|
57
|
+
## If to is a single state then just pass it on!
|
58
|
+
if !@to.is_a?(Array)
|
59
|
+
return @to
|
60
|
+
end
|
61
|
+
## If to is an Array it means decision has to be made based on branching conditions to choose the to state!
|
62
|
+
to = process_flow(@branch, base)
|
63
|
+
## If result to state coming from branching condition is not part of the set mentioned in to then next state transit is not possible!
|
64
|
+
raise InvalidState.new("Your decision condition did not lead to transition state mentioned in :to clause!") unless @to.include?(to)
|
65
|
+
to
|
66
|
+
end
|
67
|
+
|
68
|
+
def shall_i_trasit?(base)
|
69
|
+
return true unless @condition ## If no condition has been given then transition is possible!
|
70
|
+
## If condition has been given then evaluate truth or falsity for transition to be possible!
|
71
|
+
process_flow(@condition, base)
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
def process_flow(action,base)
|
76
|
+
case action
|
77
|
+
when Symbol, String
|
78
|
+
base.send(action)
|
79
|
+
when Proc
|
80
|
+
action.call(base)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Driver for Actions in FlowChart
|
86
|
+
class Action
|
87
|
+
attr_accessor :name
|
88
|
+
attr_accessor :transitions
|
89
|
+
attr_accessor :flowprocessor
|
90
|
+
|
91
|
+
def initialize(name, flowprocessor=nil, &transitions)
|
92
|
+
@name = name
|
93
|
+
@flowprocessor = flowprocessor
|
94
|
+
@transitions = Array.new
|
95
|
+
instance_eval(&transitions)
|
96
|
+
end
|
97
|
+
|
98
|
+
def process_action!(implementor_class,current_state,options_for_action)
|
99
|
+
transition = @transitions.select{ |t| t.from.include? current_state.flowstatename }.first
|
100
|
+
raise InvalidTransition.new("No transition found for action #{@name}") if transition.nil?
|
101
|
+
return false unless transition.shall_i_trasit?(implementor_class)
|
102
|
+
new_state = implementor_class.flowprocessor.flowstates[transition.get_me_next_state(implementor_class)]
|
103
|
+
raise InvalidState.new("Invalid state #{transition.to.to_s} for transition.") if new_state.nil?
|
104
|
+
current_state.process_flow(:postprocess, implementor_class)
|
105
|
+
implementor_class.previous_state = current_state.flowstatename.to_s
|
106
|
+
new_state.process_flow(:preprocess, implementor_class)
|
107
|
+
implementor_class.set_current_state(new_state,options_for_action)
|
108
|
+
true
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
def transitions(args = {})
|
113
|
+
transition = FlowChart::Transition.new(args)
|
114
|
+
@transitions << transition
|
115
|
+
end
|
116
|
+
|
117
|
+
def any
|
118
|
+
@flowprocessor.flowstates.keys
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Main Driver for FlowChart
|
123
|
+
class FlowProcessor
|
124
|
+
attr_accessor :flowstates
|
125
|
+
attr_accessor :starting_flowstate
|
126
|
+
attr_accessor :actions
|
127
|
+
|
128
|
+
def initialize(&flowprocessor)
|
129
|
+
@flowstates, @actions = Hash.new, Hash.new
|
130
|
+
begin
|
131
|
+
instance_eval(&flowprocessor)
|
132
|
+
rescue => e
|
133
|
+
p e.to_s
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
## Default state_column is assumed to be process_status if not mentioned
|
138
|
+
# You can override the default state_column by mentioning in your class
|
139
|
+
# state_column :something_else
|
140
|
+
def state_column(name = :process_status)
|
141
|
+
@state_column ||= name
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
def init_flowstate(flowstate_name)
|
146
|
+
@starting_flowstate_name = flowstate_name
|
147
|
+
end
|
148
|
+
|
149
|
+
def flowstate(*flowstatenames, &options)
|
150
|
+
flowstatenames.each do |flowstatename|
|
151
|
+
flowstate = FlowChart::State.new(flowstatename, &options)
|
152
|
+
if @flowstates.empty? || @starting_flowstate_name == flowstatename
|
153
|
+
@starting_flowstate = flowstate
|
154
|
+
end
|
155
|
+
@flowstates[flowstatename.to_sym] = flowstate
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def action(action_name, &transitions)
|
160
|
+
action = FlowChart::Action.new(action_name, self, &transitions)
|
161
|
+
@actions[action_name.to_sym] = action
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# Example of a Non-ActiveRecord Class using FlowChart in Ruby
|
2
|
+
|
3
|
+
class SampleOne
|
4
|
+
include FlowChart
|
5
|
+
attr_accessor :process_status
|
6
|
+
|
7
|
+
flowchart do
|
8
|
+
init_flowstate :init
|
9
|
+
|
10
|
+
flowstate :init do
|
11
|
+
preprocess Proc.new { |o| p "Initializing File" }
|
12
|
+
postprocess :notify_user
|
13
|
+
end
|
14
|
+
|
15
|
+
flowstate :uploaded do
|
16
|
+
preprocess Proc.new { |o| p "Validating File" }
|
17
|
+
postprocess Proc.new { |o| p "File has been uploaded in system" }
|
18
|
+
end
|
19
|
+
|
20
|
+
flowstate :open do
|
21
|
+
postprocess :notify_user
|
22
|
+
postprocess Proc.new { |o| p "File has been closed" }
|
23
|
+
end
|
24
|
+
|
25
|
+
flowstate :closed do
|
26
|
+
preprocess Proc.new { |o| p "File closed" }
|
27
|
+
postprocess :notify_user
|
28
|
+
end
|
29
|
+
|
30
|
+
action :upload do
|
31
|
+
transitions :from => :init, :to => :uploaded, :condition => :file_parsable?
|
32
|
+
end
|
33
|
+
|
34
|
+
action :process do
|
35
|
+
transitions :from => :uploaded, :to => [:open, :closed], :branch => :choose_branch
|
36
|
+
end
|
37
|
+
|
38
|
+
action :close do
|
39
|
+
transitions :from => [:init,:uploaded,:open], :to => :closed, :condition => :file_close?
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
def choose_branch
|
45
|
+
6 > 5 ? :open : :closed
|
46
|
+
end
|
47
|
+
|
48
|
+
def notify_user
|
49
|
+
p "Notifying User!"
|
50
|
+
end
|
51
|
+
|
52
|
+
def file_parsable?
|
53
|
+
3 > 2 ? true : false
|
54
|
+
end
|
55
|
+
|
56
|
+
def file_close?
|
57
|
+
1 > 0 ? true : false
|
58
|
+
end
|
59
|
+
end
|
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: flowchart
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Shuddhashil Ray
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2013-09-27 00:00:00 +05:30
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: Flowchart is a State Machine(state-action-transition) workflow for Non-ActiveRecord and ActiveRecord Model in Ruby or Rails
|
23
|
+
email: rayshuddhashil@gmail.com
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- README.rdoc
|
32
|
+
- LICENSE.txt
|
33
|
+
- flowchart.gemspec
|
34
|
+
- lib/flow_chart.rb
|
35
|
+
- lib/flowchart/flow_processor.rb
|
36
|
+
- sample/sample_one.rb
|
37
|
+
has_rdoc: true
|
38
|
+
homepage: http://github.com/raycoding/flowchart
|
39
|
+
licenses:
|
40
|
+
- MIT
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
hash: 3
|
52
|
+
segments:
|
53
|
+
- 0
|
54
|
+
version: "0"
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
hash: 3
|
61
|
+
segments:
|
62
|
+
- 0
|
63
|
+
version: "0"
|
64
|
+
requirements: []
|
65
|
+
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 1.5.3
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: State Machine and State Flow for Ruby
|
71
|
+
test_files: []
|
72
|
+
|