flowchart 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|