state_flow 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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