state_flow 0.1.0

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/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ /coverage
2
+ /pkg
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 [name of plugin creator]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,85 @@
1
+ = StateFlow
2
+ == StateFlowとは?
3
+
4
+ 状態遷移のためのDSLを提供するためのActiveRecordを拡張するプラグインです。
5
+
6
+ 以下のような記述が可能です。
7
+
8
+ class Page < ActiveRecord::Base
9
+ validates_presence_of :name
10
+
11
+ selectable_attr :status_cd do
12
+ entry '01', :editable , '編集可'
13
+ entry '04', :waiting_publish, '公開待ち'
14
+ entry '05', :publishing , '公開処理中'
15
+ entry '06', :publishing_done, '公開処理完了'
16
+ entry '07', :published , '公開済'
17
+ entry '08', :publish_failure, '公開失敗'
18
+ end
19
+
20
+ state_flow(:status_cd) do
21
+ state :created => {event(:publish) => :waiting_publish, :lock => true}
22
+
23
+ with_options(:failure => :publish_failure) do |publishing|
24
+ publishing.state :waiting_publish => :publishing, :lock => true
25
+ publishing.state :publishing => {action(:start_publish) => :publishing_done}
26
+ publishing.state :publishing_done => :published, :if => :accessable?
27
+ publishing.state :publish_failure
28
+ end
29
+
30
+ state :published
31
+ end
32
+
33
+ def start_publish
34
+ # 公開時の処理
35
+ end
36
+ end
37
+
38
+ == セットアップ
39
+ state_flowプラグインはselectable_attrに依存しています。
40
+
41
+ - selectable_attr
42
+ -- http://github.com/akm/selectable_attr
43
+ - selectable_attr_rails
44
+ -- http://github.com/akm/selectable_attr_rails
45
+
46
+ == Railsで使う場合
47
+
48
+ === プラグインとしてインストール
49
+ ruby script/plugin install git://github.com/akm/selectable_attr.git
50
+ ruby script/plugin install git://github.com/akm/selectable_attr_rails.git
51
+ ruby script/plugin install git://github.com/akm/state_flow.git
52
+ でオッケーです。
53
+
54
+ == gemの場合
55
+ まずgemcutterの設定をしていなかったら、
56
+ gem install gemcutter
57
+ gem tumble
58
+ を実行した後、
59
+ gem install selectable_attr selectable_attr_rails state_flow
60
+ を実行するとインストール完了。
61
+
62
+ で、config/initializersに以下の2つのファイルを作成すればオッケーです。
63
+
64
+ config/initializers/selectable_attr.rb
65
+
66
+ require 'selectable_attr'
67
+ require 'selectable_attr_i18n'
68
+ require 'selectable_attr_rails'
69
+ SelectableAttrRails.add_features_to_rails
70
+
71
+ config/initializers/state_flow.rb
72
+
73
+ require 'state_flow'
74
+ ActiveRecord::Base.module_eval do
75
+ include StateFlow
76
+ end
77
+
78
+
79
+ == Example
80
+ 以下のテスト用のモデルや、テストをご覧ください。
81
+ http://github.com/akm/state_flow/blob/master/spec/resources/models/page.rb
82
+ http://github.com/akm/state_flow/blob/master/spec/page_spec.rb
83
+
84
+
85
+ Copyright (c) 2009 [Takeshi AKIMA], released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,55 @@
1
+ require 'rubygems'
2
+ gem 'rspec', '>= 1.1.4'
3
+ require 'rake'
4
+ require 'rake/rdoctask'
5
+ require 'spec/rake/spectask'
6
+ require 'spec/rake/verify_rcov'
7
+
8
+ desc 'Default: run unit tests.'
9
+ task :default => :spec
10
+
11
+ task :pre_commit => [:spec, 'coverage:verify']
12
+
13
+ desc 'Run all specs under spec/**/*_spec.rb'
14
+ Spec::Rake::SpecTask.new(:spec => 'coverage:clean') do |t|
15
+ t.spec_files = FileList['spec/**/*_spec.rb']
16
+ t.spec_opts = ['--options', 'spec/spec.opts']
17
+ t.rcov_dir = 'coverage'
18
+ t.rcov = true
19
+ # t.rcov_opts = ["--include-file", "lib\/*\.rb", "--exclude", "spec\/"]
20
+ t.rcov_opts = ["--exclude", "spec\/"]
21
+ end
22
+
23
+ desc 'Generate documentation for the state_flow plugin.'
24
+ Rake::RDocTask.new(:rdoc) do |rdoc|
25
+ rdoc.rdoc_dir = 'rdoc'
26
+ rdoc.title = 'State_flow'
27
+ rdoc.options << '--line-numbers' << '--inline-source' << '-c UTF-8'
28
+ rdoc.rdoc_files.include('README*')
29
+ rdoc.rdoc_files.include('lib/**/*.rb')
30
+ end
31
+
32
+ namespace :coverage do
33
+ desc "Delete aggregate coverage data."
34
+ task(:clean) { rm_f "coverage" }
35
+
36
+ desc "verify coverage threshold via RCov"
37
+ RCov::VerifyTask.new(:verify => :spec) do |t|
38
+ t.threshold = 100.0 # Make sure you have rcov 0.7 or higher!
39
+ t.index_html = 'coverage/index.html'
40
+ end
41
+ end
42
+
43
+ begin
44
+ require 'jeweler'
45
+ Jeweler::Tasks.new do |s|
46
+ s.name = "state_flow"
47
+ s.summary = "state_flow provides a DSL for State Transition"
48
+ s.description = "state_flow provides a DSL for State Transition"
49
+ s.email = "akima@gmail.com"
50
+ s.homepage = "http://github.com/akm/state_flow/"
51
+ s.authors = ["Takeshi Akima"]
52
+ end
53
+ rescue LoadError
54
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
55
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/init.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'state_flow'
2
+
3
+ ActiveRecord::Base.module_eval do
4
+ include StateFlow
5
+ end
data/install.rb ADDED
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -0,0 +1,67 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'state_flow'
3
+ module StateFlow
4
+
5
+ class Action
6
+ attr_reader :flow
7
+ attr_accessor :success_key
8
+ attr_accessor :failure_key
9
+ attr_accessor :lock, :if, :unless
10
+
11
+ def initialize(flow)
12
+ @flow = flow
13
+ @record_key_on_thread = "#{self.class.name}_#{self.object_id}_record"
14
+ end
15
+
16
+ def record
17
+ Thread.current[@record_key_on_thread]
18
+ end
19
+
20
+ def record=(value)
21
+ Thread.current[@record_key_on_thread] = value
22
+ end
23
+
24
+ def process(record)
25
+ return if self.if && !call_or_send(self.if, record)
26
+ return if self.unless && call_or_send(self.unless, record)
27
+ self.record = record
28
+ begin
29
+ block_given? ? yield(self) : proceed
30
+ ensure
31
+ self.record = nil
32
+ end
33
+ end
34
+
35
+ def proceed
36
+ flow.process_with_log(self.record, success_key, failure_key)
37
+ end
38
+
39
+ def call_or_send(filter, record)
40
+ filter.respond_to?(:call) ? filter.call(record) :
41
+ filter.is_a?(Array) ? record.send(*filter) : record.send(filter)
42
+ end
43
+
44
+ def inspect
45
+ result = "<#{self.class.name}"
46
+ result << " @name=#{@name.inspect}" if @name
47
+ result << " @success_key=#{@success_key.inspect}" if @success_key
48
+ result << " @failure_key=#{@failure_key.inspect}" if @failure_key
49
+ result << " @lock=#{@lock.inspect}" if @lock
50
+ result << " @if=#{@if.inspect}" if @if
51
+ result << " @unless=#{@unless.inspect}" if @unless
52
+ result << '>'
53
+ end
54
+
55
+ module Executable
56
+ attr_accessor :action
57
+
58
+ def options ; @options ||= {} ; end
59
+ def options=(value); @options = value; end
60
+
61
+ def success_key; action.success_key if action; end
62
+ def failure_key; action.failure_key if action; end
63
+ end
64
+
65
+ end
66
+
67
+ end
@@ -0,0 +1,108 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'state_flow'
3
+ module StateFlow
4
+
5
+ class Base
6
+ include Builder
7
+
8
+ module ClassMethods
9
+
10
+ def process_state(selectable_attr, *keys, &block)
11
+ options = {
12
+ :transactional => false, # :each, # :all
13
+ }.update(keys.extract_options!)
14
+ options[:transactional] = :each if options[:transactional] == true
15
+ state_flow = state_flow_for(selectable_attr)
16
+ raise ArgumentError, "state_flow not found: #{selectable_attr.inspect}" unless state_flow
17
+ transaction_if_need(options[:transactional] == :all) do
18
+ keys.each do |key|
19
+ entry = state_flow[key]
20
+ raise ArgumentError, "entry not found: #{key.inspect}" unless entry
21
+ transaction_if_need(options[:transactional] == :each) do
22
+ entry.process(&block)
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ def transaction_if_need(with_transaction, &block)
29
+ if with_transaction
30
+ self.transaction(&block)
31
+ else
32
+ yield
33
+ end
34
+ end
35
+ end
36
+
37
+ attr_reader :klass, :attr_name, :attr_key_name, :status_keys
38
+ attr_reader :entries
39
+ def initialize(klass, attr_name, attr_key_name)
40
+ @klass, @attr_name, @attr_key_name = klass, attr_name, attr_key_name
41
+ @status_keys = klass.send(@attr_key_name.to_s.pluralize).map{|s| s.to_sym}
42
+ @entries = []
43
+ end
44
+
45
+ def state_cd_by_key(key)
46
+ @state_cd_by_key_method_name ||= "#{klass.enum_base_name(attr_name)}_id_by_key"
47
+ klass.send(@state_cd_by_key_method_name, key)
48
+ end
49
+
50
+ def entry_for(key)
51
+ unless @entry_hash
52
+ @entry_hash = entries.inject({}) do |dest, entry|
53
+ dest[entry.key] = entry
54
+ dest
55
+ end
56
+ end
57
+ @entry_hash[key]
58
+ end
59
+ alias_method :[], :entry_for
60
+
61
+ def process_with_log(record, success_key, failure_key)
62
+ origin_state = record.send(attr_name)
63
+ origin_state_key = record.send(attr_key_name)
64
+ begin
65
+ yield(record) if block_given?
66
+ # success_keyが指定されない場合、その変更はアクションとして指定されたメソッドに依存します。
67
+ if success_key
68
+ record.send("#{attr_key_name}=", success_key)
69
+ record.save!
70
+ end
71
+ rescue Exception => error
72
+ log_attrs = {
73
+ :target => record,
74
+ :origin_state => origin_state,
75
+ :origin_state_key => origin_state_key ? origin_state_key.to_s : nil,
76
+ :dest_state => self.state_cd_by_key(success_key),
77
+ :dest_state_key => success_key ? success_key.to_s : nil
78
+ }
79
+ StateFlow::Log.error(error, log_attrs)
80
+ if failure_key
81
+ retry_count = 0
82
+ begin
83
+ record.send("#{attr_key_name}=", failure_key)
84
+ record.save!
85
+ rescue Exception => fatal_error
86
+ if retry_count == 0
87
+ retry_count += 1
88
+ record.attributes = record.class.find(record.id).attributes
89
+ retry
90
+ end
91
+ StateFlow::Log.fatal(fatal_error, log_attrs)
92
+ raise fatal_error
93
+ end
94
+ end
95
+ raise error
96
+ end
97
+ end
98
+
99
+ def inspect
100
+ result = "<#{self.class.name} @attr_name=#{@attr_name.inspect} @attr_key_name=#{@attr_key_name.inspect}"
101
+ result << " @klass=\"#{@klass.name}\""
102
+ result << " @entries=#{@entries.inspect}"
103
+ result << '>'
104
+ end
105
+
106
+ end
107
+
108
+ end
@@ -0,0 +1,193 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'state_flow'
3
+ module StateFlow
4
+
5
+ module Builder
6
+ module ClientClassMethods
7
+ def state_flow_for(selectable_attr)
8
+ return nil unless @state_flows
9
+ @state_flows.detect{|flow| flow.attr_name == selectable_attr}
10
+ end
11
+
12
+ def state_flow(selectable_attr, options = nil, &block)
13
+ options = {
14
+ :attr_key_name => "#{self.enum_base_name(selectable_attr)}_key".to_sym
15
+ }.update(options || {})
16
+ flow = Base.new(self, selectable_attr, options[:attr_key_name])
17
+ flow.instance_eval(&block)
18
+ flow.setup_events
19
+ @state_flows ||= []
20
+ @state_flows << flow
21
+ flow
22
+ end
23
+ end
24
+
25
+ def new_entry(key)
26
+ @entry_hash = nil
27
+ result = Entry.new(self, key)
28
+ entries << result
29
+ result
30
+ end
31
+
32
+ def state(*args)
33
+ raise_invalid_state_argument if args.length > 2
34
+ if args.length == 2
35
+ # 引数が2個ならできるだけ一つのHashにまとめます。
36
+ case args.first
37
+ when Hash then
38
+ return state(args.first.update(args.last))
39
+ when Symbol, String
40
+ return state({args.first => nil}.update(args.last))
41
+ else
42
+ raise_invalid_state_argument
43
+ end
44
+ end
45
+ # 引数が一つだけになってます
46
+ arg = args.first
47
+ case arg
48
+ when Symbol, String
49
+ return state({args.first => nil})
50
+ when Hash then
51
+ # through
52
+ else
53
+ raise_invalid_state_argument
54
+ end
55
+ # 引数がHash一つだけの場合
56
+ base_options = extract_common_options(arg)
57
+ arg.each do |key, value|
58
+ entry = new_entry(key)
59
+ build_entry(entry, value, base_options)
60
+ end
61
+ end
62
+
63
+ def action(name)
64
+ NamedAction.new(self, name)
65
+ end
66
+
67
+ def event(name)
68
+ Event.new(self, name)
69
+ end
70
+
71
+ def setup_events
72
+ event_defs = {}
73
+ entries.each do |entry|
74
+ origin_key = entry.key
75
+ entry.events.each do |event|
76
+ event_trans = event_defs[event.name] ||= {}
77
+ event_trans[origin_key] = [event.success_key, event.failure_key]
78
+ end
79
+ end
80
+ event_defs.each do |event_name, trans|
81
+ method_def = <<-"EOS"
82
+ def #{event_name}
83
+ @state_flow ||= self.class.state_flow_for(:#{attr_name})
84
+ @#{event_name}_transitions ||= #{trans.inspect}
85
+ @state_flow.process_with_log(self,
86
+ *@#{event_name}_transitions[#{attr_key_name}])
87
+ end
88
+ EOS
89
+ if klass.instance_methods.include?(event_name)
90
+ klass.logger.warn("state_flow plugin was going to define #{event_name} but didn't do it because #{event_name} does exist.")
91
+ else
92
+ klass.module_eval(method_def, __FILE__, __LINE__)
93
+ end
94
+ end
95
+ end
96
+
97
+ private
98
+
99
+ def build_entry(entry, options_or_success_key, base_options)
100
+ if options_or_success_key.nil?
101
+ return null_action_entry(entry, base_options)
102
+ end
103
+ case options_or_success_key
104
+ when String, Symbol then
105
+ return null_action_entry(entry, base_options, options_or_success_key.to_sym)
106
+ when Action then
107
+ entry.action = setup_action(options_or_success_key, base_options)
108
+ return entry
109
+ when Hash then
110
+ options = options_or_success_key
111
+ prior_options = extract_common_options(options)
112
+ options_keys = options.keys
113
+ if options_keys.all?{|key| key.is_a?(Action)}
114
+ build_action(entry, options, base_options.merge(prior_options))
115
+ elsif options_keys.all?{|key| key.is_a?(Event)}
116
+ raise_invalid_state_argument unless entry.is_a?(Entry)
117
+ build_events(entry, options, base_options.merge(prior_options))
118
+ else
119
+ raise_invalid_state_argument
120
+ end
121
+ when Array then
122
+ options_or_success_key.each do |options|
123
+ each_base_options = base_options.merge(extract_common_options(options))
124
+ build_entry(entry, options, each_base_options)
125
+ end
126
+ else
127
+ raise_invalid_state_argument
128
+ end
129
+ end
130
+
131
+ def null_action_entry(entry, options, success_key = nil)
132
+ action = Action.new(self)
133
+ options = options.dup
134
+ entry.action = setup_action(action, options, success_key)
135
+ entry.options = options
136
+ entry
137
+ end
138
+
139
+ def build_action(entry, action_hash, options)
140
+ raise_invalid_state_argument unless action_hash.length == 1
141
+ options = options.dup
142
+ entry.action = setup_action(action_hash.keys.first, options, action_hash.values.first)
143
+ entry.options = options
144
+ end
145
+
146
+ def setup_action(action, options, success_key = nil)
147
+ action.success_key = success_key.to_sym if success_key
148
+ action.failure_key = options.delete(:failure)
149
+ action.lock = options.delete(:lock)
150
+ action.if = options.delete(:if)
151
+ action.unless = options.delete(:unless)
152
+ action
153
+ end
154
+
155
+
156
+ def build_events(entry, event_hash, options)
157
+ event_hash.each do |event, value|
158
+ build_entry(event, value, options)
159
+ entry.events << event
160
+ end
161
+ end
162
+
163
+ COMMON_OPTION_NAMES = [:lock, :if, :unless, :failure]
164
+
165
+ def extract_common_options(hash)
166
+ COMMON_OPTION_NAMES.inject({}) do |dest, name|
167
+ value = hash.delete(name)
168
+ dest[name] = value if value
169
+ dest
170
+ end
171
+ end
172
+
173
+ def raise_invalid_state_argument
174
+ raise ArgumentError, state_argument_pattern
175
+ end
176
+
177
+ def state_argument_pattern
178
+ descriptions = <<-"EOS"
179
+ state arguments pattern:
180
+ * state :<state_name>
181
+ * state :<state_name> => :<new_state_name>
182
+ * state :<state_name> => action(:<method_name>)
183
+ * state :<state_name> => { action(:<method_name>) => :<new_state_name>}
184
+ * state :<state_name> => { event(:<event_name1>) => :<new_state_name>, event(:<event_name2>) => :<new_state_name>}
185
+ * state :<state_name> => { event(:<event_name1>) => { action(:<method_name1>) => :<new_state_name>}, event(:<event_name2>) => {action(:<method_name1>) => :<new_state_name>} }
186
+ And you can append :lock, :if, :unless option in Hash
187
+ EOS
188
+ descriptions.split(/$/).map{|s| s.sub(/^\s{8}/, '')}.join("\n")
189
+ end
190
+
191
+ end
192
+
193
+ end
@@ -0,0 +1,44 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'state_flow'
3
+ module StateFlow
4
+
5
+ class Entry
6
+ include Action::Executable
7
+ attr_reader :flow, :key
8
+
9
+ def initialize(flow, key)
10
+ @flow = flow
11
+ @key = key.to_s.to_sym
12
+ end
13
+
14
+ def events
15
+ @events ||= [];
16
+ end
17
+
18
+ def event_for(name)
19
+ events.detect{|event| event.name == name}
20
+ end
21
+
22
+ def process(&block)
23
+ value = flow.state_cd_by_key(key)
24
+ find_options = {
25
+ :order => "id asc",
26
+ :conditions => ["#{flow.attr_name} = ?", value]
27
+ }
28
+ find_options[:lock] = action.lock if action.lock
29
+ if record = flow.klass.find(:first, find_options)
30
+ action.process(record, &block) if action
31
+ end
32
+ end
33
+
34
+ def inspect
35
+ result = "<#{self.class.name} @key=#{@key.inspect}"
36
+ result << " @action=#{@action.inspect}" if @action
37
+ if @events && !@events.empty?
38
+ result << " @events=#{@events.sort_by{|event|event.name.to_s}.inspect}"
39
+ end
40
+ result << ">"
41
+ end
42
+ end
43
+
44
+ end
@@ -0,0 +1,21 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'state_flow'
3
+ module StateFlow
4
+
5
+ class Event
6
+ include Action::Executable
7
+ attr_reader :flow, :name
8
+
9
+ def initialize(flow, name)
10
+ @flow = flow
11
+ @name = name.to_s.to_sym
12
+ end
13
+
14
+ def inspect
15
+ result = "<#{self.class.name} @name=#{@name.inspect}"
16
+ result << " @action=#{@action.inspect}" if @action
17
+ result << ">"
18
+ end
19
+ end
20
+
21
+ end
@@ -0,0 +1,30 @@
1
+ module StateFlow
2
+ class Log < ActiveRecord::Base
3
+ set_table_name 'state_flow_logs'
4
+
5
+ belongs_to :target, :polymorphic => true
6
+
7
+ class << self
8
+ def fatal(message, options = nil); write(message, :fatal, options); end
9
+ def error(message, options = nil); write(message, :error, options); end
10
+ def warn (message, options = nil); write(message, :warn , options); end
11
+ def info (message, options = nil); write(message, :info , options); end
12
+ def debug(message, options = nil); write(message, :debug, options); end
13
+
14
+ private
15
+ def write(message, level, options = nil)
16
+ log = self.new(options || {})
17
+ log.level = level.to_s
18
+ log.descriptions = message.is_a?(Exception) ? format_exception(message) : message
19
+ unless log.save
20
+ logger.error(log.inspect)
21
+ end
22
+ end
23
+
24
+ def format_exception(exception)
25
+ '%s\n %s' % [exception.to_s, exception.backtrace.join("\n ")]
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,19 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'state_flow'
3
+ module StateFlow
4
+
5
+ class NamedAction < Action
6
+ attr_reader :name
7
+ def initialize(flow, name)
8
+ super(flow)
9
+ @name = name.to_s.to_sym
10
+ end
11
+
12
+ def proceed
13
+ flow.process_with_log(self.record, success_key, failure_key) do
14
+ self.record.send(name)
15
+ end
16
+ end
17
+ end
18
+
19
+ end
data/lib/state_flow.rb ADDED
@@ -0,0 +1,20 @@
1
+ module StateFlow
2
+ autoload :Base, 'state_flow/base'
3
+ autoload :Builder, 'state_flow/builder'
4
+ autoload :Action, 'state_flow/action'
5
+ autoload :NamedAction, 'state_flow/named_action'
6
+ autoload :Event, 'state_flow/event'
7
+ autoload :Entry, 'state_flow/entry'
8
+ autoload :Log, 'state_flow/log'
9
+
10
+ # autoload :ActiveRecord, 'state_flow/active_record'
11
+
12
+ def self.included(mod)
13
+ mod.module_eval do
14
+ extend ::StateFlow::Builder::ClientClassMethods
15
+ extend ::StateFlow::Base::ClassMethods
16
+ # include ::StateFlow::ActiveRecord if mod.ancestors.map{|m| m.name}.include?('ActiveRecord::Base')
17
+ end
18
+ end
19
+
20
+ end
data/spec/.gitignore ADDED
@@ -0,0 +1 @@
1
+ /*.sqlite3