state_flow 0.1.0 → 0.2.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.
@@ -0,0 +1,39 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'state_flow'
3
+ module StateFlow
4
+
5
+ class ExceptionHandler < Event
6
+ attr_reader :exceptions
7
+ attr_reader :recovering, :rolling_back, :logging_error
8
+
9
+ def initialize(origin, *exceptions, &block)
10
+ options = exceptions.extract_options!
11
+ @exceptions = exceptions
12
+ super(origin, &block)
13
+ @recovering = options[:recovering] || false
14
+ @rolling_back = options[:rolling_back] || options[:rollback] || false
15
+ @logging_error = options[:logging]
16
+ end
17
+
18
+ def match?(exception)
19
+ prepare_exceptions
20
+ exceptions.any?{|klass| exception.is_a?(klass)}
21
+ end
22
+
23
+ def process(context)
24
+ context.recovered_exceptions << context.exceptions.last if recovering
25
+ context.transaction_rollback if rolling_back
26
+ context.record_reload_if_possible
27
+ super
28
+ end
29
+
30
+ private
31
+ def prepare_exceptions
32
+ return if exceptions.all?{|ex| ex.is_a?(Class)}
33
+ @exceptions = exceptions.map do |ex|
34
+ ex.is_a?(Class) ? ex : ex.to_s.constantize
35
+ end
36
+ end
37
+ end
38
+
39
+ end
@@ -0,0 +1,25 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'state_flow'
3
+ module StateFlow
4
+
5
+ module ExceptionHandlerClient
6
+ def exception_handling(context)
7
+ begin
8
+ yield
9
+ rescue Exception => exception
10
+ context.exceptions << exception
11
+ context.trace(exception)
12
+ handlers = events.select{|ev| ev.is_a?(ExceptionHandler)}
13
+ handlers.each do |handler|
14
+ next unless handler.match?(exception)
15
+ handler.process(context)
16
+ break
17
+ end
18
+ raise exception unless context.recovered?(exception)
19
+ end
20
+ end
21
+
22
+ end
23
+
24
+
25
+ end
@@ -0,0 +1,21 @@
1
+ require 'state_flow'
2
+ module StateFlow
3
+
4
+ class Guard < Element
5
+ include EventClient
6
+ include ActionClient
7
+
8
+ def match?(context)
9
+ true
10
+ end
11
+
12
+ def process(context)
13
+ exception_handling(context) do
14
+ action.process(context) if action
15
+ update_to_destination(context)
16
+ end
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,28 @@
1
+ require 'state_flow'
2
+ module StateFlow
3
+
4
+ module GuardClient
5
+ def guards
6
+ @guards ||= []
7
+ end
8
+
9
+ def guard(method_name, &block)
10
+ result = NamedGuard.new(self, method_name, &block)
11
+ guards << result
12
+ result
13
+ end
14
+
15
+ def guard_else(&block)
16
+ result = Guard.new(self, &block)
17
+ guards << result
18
+ result
19
+ end
20
+
21
+ def guard_for(context)
22
+ guards.detect{|guard| guard.match?(context)}
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+
@@ -0,0 +1,56 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'state_flow'
3
+ module StateFlow
4
+
5
+ class NamedEvent < Event
6
+ attr_reader :name
7
+ def initialize(origin, name, &block)
8
+ @name = name
9
+ super(origin, &block)
10
+ end
11
+
12
+ def process(context)
13
+ block = state.ancestors_exception_handled_proc(context) do
14
+ super
15
+ end
16
+ block.call
17
+ end
18
+
19
+ class << self
20
+ def build_event_methods(flow)
21
+ named_events = []
22
+ flow.all_states.each do |state_name, state|
23
+ state.visit do |event|
24
+ named_events << event if event.is_a?(NamedEvent)
25
+ [:events, :guards, :action]
26
+ end
27
+ end
28
+ method_name_to_events = {}
29
+ named_events.each do |ev|
30
+ method_name_to_events[ev.name] ||= []
31
+ method_name_to_events[ev.name] << ev
32
+ end
33
+ method_name_to_events.each do |name, events|
34
+ flow.klass.module_eval do
35
+ # イベントを通知するときに呼び出されるメソッド
36
+ define_method(name) do |*args|
37
+ result = nil
38
+ events.each do |event|
39
+ if event.state.include?(self.send(flow.attr_key_name))
40
+ context = flow.prepare_context(self, args.first)
41
+ result = context.process(event)
42
+ break
43
+ end
44
+ end
45
+ result # return
46
+ end
47
+
48
+ end
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+ end
55
+
56
+ end
@@ -0,0 +1,17 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'state_flow'
3
+ module StateFlow
4
+
5
+ class NamedGuard < Guard
6
+ attr_reader :name
7
+ def initialize(origin, name, &block)
8
+ @name = name
9
+ super(origin, &block)
10
+ end
11
+
12
+ def match?(context)
13
+ context.record_send(name)
14
+ end
15
+ end
16
+
17
+ end
@@ -0,0 +1,91 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'state_flow'
3
+ module StateFlow
4
+
5
+ class State
6
+ include EventClient
7
+ include GuardClient
8
+ include ActionClient
9
+ include ElementVisitable
10
+
11
+ attr_reader :name, :flow, :parent
12
+ attr_accessor :termination
13
+ def initialize(flow_or_parent, name, &block)
14
+ @name = name
15
+ @parent = flow_or_parent if flow_or_parent.is_a?(State)
16
+ @flow = flow_or_parent.is_a?(State) ? flow_or_parent.flow : flow_or_parent
17
+ @concreate = @flow.state_cd_by_key(@name)
18
+ instance_eval(&block) if block
19
+ end
20
+
21
+ def state(name, &block)
22
+ result = State.new(self, name, &block)
23
+ children << result
24
+ result
25
+ end
26
+ alias_method :from, :state
27
+ alias_method :group, :state
28
+ alias_method :state_group, :state
29
+
30
+ def termination(name = nil)
31
+ result = name ? state(name) : self
32
+ result.termination = true
33
+ result
34
+ end
35
+
36
+ def children
37
+ @children ||= []
38
+ end
39
+
40
+ def descendants
41
+ [self, children.map{|c|c.descendants}].flatten
42
+ end
43
+
44
+ def include?(state_or_name)
45
+ name = state_or_name.is_a?(State) ? state_or_name.name : state_or_name
46
+ descendants.any?{|state| state.name == name}
47
+ end
48
+
49
+ def concrete?
50
+ @concreate
51
+ end
52
+
53
+ private
54
+ # for EventClient
55
+ def origin
56
+ self
57
+ end
58
+
59
+ public
60
+ def process(context)
61
+ context.trace(self)
62
+ block = ancestors_exception_handled_proc(context) do
63
+ guard = guard_for(context)
64
+ return guard.process(context) if guard
65
+ return action.process(context) if action
66
+ end
67
+ block.call
68
+ end
69
+
70
+ def ancestors_exception_handled_proc(context, &block)
71
+ result = Proc.new{ exception_handling(context, &block) }
72
+ parent ? parent.ancestors_exception_handled_proc(context, &result) : result
73
+ end
74
+
75
+ def name_path(separator = '>')
76
+ result = []
77
+ current = self
78
+ while current
79
+ result << current.name
80
+ current = current.parent
81
+ end
82
+ result.reverse.join(separator)
83
+ end
84
+
85
+ def inspect
86
+ "#<%s:%#x @name=%s>" % [self.class.name, self.object_id, name_path.inspect]
87
+ end
88
+
89
+ end
90
+
91
+ end
data/lib/state_flow.rb CHANGED
@@ -1,19 +1,33 @@
1
1
  module StateFlow
2
2
  autoload :Base, 'state_flow/base'
3
- autoload :Builder, 'state_flow/builder'
3
+ autoload :Context, 'state_flow/context'
4
+
5
+ autoload :State, 'state_flow/state'
6
+
7
+ autoload :Element, 'state_flow/element'
8
+ autoload :ElementVisitable, 'state_flow/element_visitable'
9
+
4
10
  autoload :Action, 'state_flow/action'
5
- autoload :NamedAction, 'state_flow/named_action'
11
+ autoload :ActionClient, 'state_flow/action_client'
12
+
13
+ autoload :Guard, 'state_flow/guard'
14
+ autoload :GuardClient, 'state_flow/guard_client'
15
+ autoload :NamedGuard, 'state_flow/named_guard'
16
+
6
17
  autoload :Event, 'state_flow/event'
7
- autoload :Entry, 'state_flow/entry'
18
+ autoload :EventClient, 'state_flow/event_client'
19
+ autoload :NamedEvent, 'state_flow/named_event'
20
+ autoload :ActionEvent, 'state_flow/action_event'
21
+ autoload :ExceptionHandler, 'state_flow/exception_handler'
22
+ autoload :ExceptionHandlerClient, 'state_flow/exception_handler_client'
23
+
8
24
  autoload :Log, 'state_flow/log'
9
25
 
10
26
  # autoload :ActiveRecord, 'state_flow/active_record'
11
27
 
12
28
  def self.included(mod)
13
29
  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')
30
+ extend(Base::ClientClassMethods)
17
31
  end
18
32
  end
19
33
 
data/spec/database.yml CHANGED
@@ -21,5 +21,3 @@ postgresql:
21
21
  host: localhost
22
22
  username: postgres
23
23
  password:
24
- allow_concurrency: true
25
- pool: 30