hifsm 0.3.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2dd540fa33580b8e82c96d82a1746aa5016ab3c6
4
- data.tar.gz: ab0492f94873e14a2f75d1e3fd32ae764ed652c1
3
+ metadata.gz: 313a9e688988c6dac1ee778973a602db61af4ca2
4
+ data.tar.gz: cf7dc5e882dbf4f8dfaf34f211aa04d136474b01
5
5
  SHA512:
6
- metadata.gz: 258cd2e2f5a18942a0ee40a96779246ba0b99adc4659834460ac482f96882cef9c2d5ca4f7e49301df4cb759ea12f4969a8f2aeb00554af5f092664c419b089e
7
- data.tar.gz: 56cf2f726e53af3fdfa98067030448cbcd86a9306937e30d3ab75ab0c35bfc24246371df1fb1b7e202c7ccf54a443762bb1e126582d2462f36c5139438a244f7
6
+ metadata.gz: b585b14728b541d4d2863d71e7ac55a59699f71d33ed48ef8b9a366b8f2f2440b8426fbad9287564748e6acb0fb05308f476b66aa72cd61d70877d9691db30d9
7
+ data.tar.gz: 53df6c486ca83c6745fca49e9cec581348f5b6919d3efcfd76aa6316682d4d3c6dafb31342777d3530838852a9c0665cebfa3b3bdcfd3f0bc319b8e221854f1a
data/README.md CHANGED
@@ -21,7 +21,7 @@ Or install it yourself as:
21
21
 
22
22
  $ gem install hifsm
23
23
 
24
- I prefer 1.8-style hashes, and since no advanced Ruby magic used it should work in 1.8, but only tested in 2+.
24
+ Written in Ruby 1.8-style (hashes, lambdas), but few non-essential 1.9 niceties used, tested in 2+.
25
25
 
26
26
  __This is in early development, so be careful.__
27
27
 
@@ -196,20 +196,28 @@ Add column to your database which would hold the state, and then:
196
196
 
197
197
  ```ruby
198
198
  class Order < ActiveRecord::Base
199
- hifsm do
199
+ hifsm :status do
200
200
  state :draft, :initial => true
201
201
  state :processing do
202
202
  state :packaging, :initial => true
203
203
  state :delivering
204
+
205
+ event :start_delivery, :from => :packaging, :to => :delivering
204
206
  end
205
207
  state :done
206
208
  state :cancelled
207
209
 
208
210
  event :start_processing, :from => :draft, :to => :processing
209
- event :cancel, :to => :cancelled
211
+ event :cancel!, :to => :cancelled
210
212
  end
211
213
  end
212
- Order.new # draft
214
+ order = Order.create # draft
215
+ order.start_processing.save # 'processing.packaging'
216
+
217
+ # scopes defined automatically. parent scopes looked up via like "processing.%"
218
+ Order.processing.first.start_delivery.save
219
+ Order.processing_packaging.first # nil
220
+ Order.processing_delivering.first.cancel!.save # save is never called inisde hifsm
213
221
 
214
222
  ```
215
223
 
@@ -12,6 +12,16 @@ module Hifsm
12
12
  include Hifsm.fsm_module(column, &block)
13
13
  before_save "hifsm_write_#{column}_attribute"
14
14
 
15
+ send("#{column}_machine_definition").all_states.each do |st|
16
+ state_name = st.to_s
17
+ scope_name = state_name.gsub('.', '_')
18
+ if st.sub_fsm
19
+ scope scope_name, lambda { where(arel_table[column].matches(state_name + '.%')) }
20
+ else
21
+ scope scope_name, lambda { where(column => state_name) }
22
+ end
23
+ end
24
+
15
25
  define_method "#{column}=" do |value|
16
26
  raise 'not (sure will be) implemented'
17
27
  end
data/lib/hifsm/fsm.rb CHANGED
@@ -23,24 +23,7 @@ module Hifsm
23
23
  @machine_class.new(self, target, initial_state)
24
24
  end
25
25
 
26
- def all_events
27
- @states.collect {|name, st| st.events }.flatten.uniq
28
- end
29
-
30
- def initial_state!
31
- @initial_state || raise(Hifsm::MissingState.new("<initial>"))
32
- end
33
-
34
- def get_state!(name)
35
- top_level_state, rest = name.to_s.split('.', 2)
36
- st = @states[top_level_state] || raise(Hifsm::MissingState.new(name.to_s))
37
- if rest
38
- st.get_substate!(rest)
39
- else
40
- st
41
- end
42
- end
43
-
26
+ #DSL
44
27
  def event(name, options, &block)
45
28
  ev = Hifsm::Event.new(name, get_state!(options[:to]), array_wrap(options[:guard]))
46
29
  from_states = array_wrap(options[:from])
@@ -58,6 +41,32 @@ module Hifsm
58
41
  st.instance_eval(&block) if block
59
42
  end
60
43
 
44
+ # internals
45
+ def all_events
46
+ @states.flat_map {|name, st| st.events }.uniq
47
+ end
48
+
49
+ def all_states
50
+ @states.flat_map do |state_name, st|
51
+ # state should delegate to sub_fsm :)
52
+ [st] + (st.sub_fsm && st.sub_fsm.all_states || [])
53
+ end
54
+ end
55
+
56
+ def initial_state!
57
+ @initial_state || raise(Hifsm::MissingState.new("<initial>"))
58
+ end
59
+
60
+ def get_state!(name)
61
+ top_level_state, rest = name.to_s.split('.', 2)
62
+ st = @states[top_level_state] || raise(Hifsm::MissingState.new(name.to_s))
63
+ if rest
64
+ st.get_substate!(rest)
65
+ else
66
+ st
67
+ end
68
+ end
69
+
61
70
  def to_module
62
71
  @fsm_module
63
72
  end
@@ -73,7 +82,17 @@ module Hifsm
73
82
  machine_var = "@#{name}_machine"
74
83
  machine_name = "#{name}_machine"
75
84
 
76
- Module.new.module_exec do
85
+ module_class_methods = Module.new do
86
+ define_method("#{machine_name}_definition") { fsm }
87
+ end
88
+
89
+ Module.new do
90
+ const_set('ClassMethods', module_class_methods)
91
+ def self.included(base)
92
+ base.class_exec do
93
+ extend const_get('ClassMethods')
94
+ end
95
+ end
77
96
 
78
97
  # <state>_machine returns machine instance
79
98
  define_method(machine_name) do
@@ -92,8 +111,6 @@ module Hifsm
92
111
  fsm.all_events.each do |event_name, event|
93
112
  define_method(event_name) {|*args| send(machine_name).fire(event_name, *args) }
94
113
  end
95
-
96
- self # return module
97
114
  end
98
115
  end
99
116
  end
data/lib/hifsm/state.rb CHANGED
@@ -2,6 +2,8 @@ module Hifsm
2
2
  class State
3
3
  CALLBACKS = [:before_enter, :before_exit, :after_enter, :after_exit].freeze
4
4
 
5
+ attr_reader :sub_fsm
6
+
5
7
  def initialize(fsm, name, parent = nil)
6
8
  @fsm = fsm
7
9
  @name = name
@@ -13,11 +15,7 @@ module Hifsm
13
15
  @transitions = Hash.new {|h, key| h[key] = Array.new }
14
16
  end
15
17
 
16
- def add_transition(ev)
17
- name = ev.name.to_s
18
- @transitions[name].push ev
19
- end
20
-
18
+ # DSL
21
19
  def action(&block)
22
20
  @action = block
23
21
  end
@@ -30,10 +28,38 @@ module Hifsm
30
28
  sub_fsm!.event(*args, &block)
31
29
  end
32
30
 
31
+ CALLBACKS.each do |cb|
32
+ define_method(cb) { |&block| @callbacks[cb].add(&block) }
33
+ end
34
+
35
+ # internals
36
+ def act!(target, *args)
37
+ @parent.act!(target, *args) if @parent
38
+ @action && Callbacks.invoke(target, @action, *args)
39
+ end
40
+
41
+ def add_transition(ev)
42
+ name = ev.name.to_s
43
+ @transitions[name].push ev
44
+ end
45
+
46
+ def enter!
47
+ if @sub_fsm
48
+ @sub_fsm.initial_state!
49
+ else
50
+ self
51
+ end
52
+ end
53
+
33
54
  def events
34
55
  @transitions.keys + (@sub_fsm && @sub_fsm.all_events || [])
35
56
  end
36
57
 
58
+ def get_substate!(name)
59
+ raise Hifsm::MissingState.new(name.to_s) unless @sub_fsm
60
+ @sub_fsm.get_state!(name)
61
+ end
62
+
37
63
  def fire(target, event_name, *args, &new_state_callback)
38
64
  event_name = event_name.to_s
39
65
  @transitions[event_name].each do |ev|
@@ -57,32 +83,10 @@ module Hifsm
57
83
  raise Hifsm::MissingTransition.new(to_s, event_name)
58
84
  end
59
85
 
60
- CALLBACKS.each do |cb|
61
- define_method(cb) { |&block| @callbacks[cb].add(&block) }
62
- end
63
-
64
86
  def trigger(target, cb, *args)
65
87
  @callbacks[cb].trigger(target, *args)
66
88
  end
67
89
 
68
- def act!(target, *args)
69
- @parent.act!(target, *args) if @parent
70
- @action && Callbacks.invoke(target, @action, *args)
71
- end
72
-
73
- def enter!
74
- if @sub_fsm
75
- @sub_fsm.initial_state!
76
- else
77
- self
78
- end
79
- end
80
-
81
- def get_substate!(name)
82
- raise Hifsm::MissingState.new(name.to_s) unless @sub_fsm
83
- @sub_fsm.get_state!(name)
84
- end
85
-
86
90
  def to_s
87
91
  if @parent
88
92
  "#{@parent.to_s}.#{@name.to_s}"
@@ -93,7 +97,7 @@ module Hifsm
93
97
 
94
98
  private
95
99
  def sub_fsm!
96
- # FIXME too much coupling
100
+ # FIXME .name = too much coupling
97
101
  @sub_fsm ||= Hifsm::FSM.new(@fsm.name, self)
98
102
  end
99
103
  end
data/lib/hifsm/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Hifsm
2
- VERSION = "0.3.0"
2
+ VERSION = "0.3.1"
3
3
  end
@@ -69,6 +69,14 @@ class TestActiverecrodAdapter < Minitest::Test
69
69
  assert_equal 'off', SodaMachine.where(:id => @machine.id).pluck(:state).first
70
70
  end
71
71
 
72
+ def test_leaf_scope
73
+ refute_nil SodaMachine.broken.first
74
+ end
75
+
76
+ def test_parent_scope
77
+ refute_nil SodaMachine.on.first
78
+ end
79
+
72
80
  private
73
81
  def insert_record(address, state)
74
82
  insert_manager = Arel::InsertManager.new(SodaMachine)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hifsm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vladimir Meremyanin