davidlee-state-fu 0.3.1 → 0.10.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/README.textile +124 -34
- data/Rakefile +36 -30
- data/lib/no_stdout.rb +1 -1
- data/lib/state-fu.rb +9 -8
- data/lib/state_fu/active_support_lite/array/access.rb +12 -5
- data/lib/state_fu/active_support_lite/array/conversions.rb +10 -4
- data/lib/state_fu/active_support_lite/array/extract_options.rb +5 -4
- data/lib/state_fu/active_support_lite/array/grouping.rb +7 -4
- data/lib/state_fu/active_support_lite/array/random_access.rb +4 -3
- data/lib/state_fu/active_support_lite/array/wrapper.rb +4 -3
- data/lib/state_fu/active_support_lite/array.rb +3 -1
- data/lib/state_fu/active_support_lite/blank.rb +18 -9
- data/lib/state_fu/active_support_lite/cattr_reader.rb +4 -1
- data/lib/state_fu/active_support_lite/keys.rb +8 -3
- data/lib/state_fu/active_support_lite/misc.rb +6 -4
- data/lib/state_fu/active_support_lite/module/delegation.rb +130 -0
- data/lib/state_fu/active_support_lite/module.rb +1 -0
- data/lib/state_fu/active_support_lite/object.rb +5 -2
- data/lib/state_fu/active_support_lite/string.rb +6 -1
- data/lib/state_fu/active_support_lite/symbol.rb +2 -1
- data/lib/state_fu/applicable.rb +41 -0
- data/lib/state_fu/{helper.rb → arrays.rb} +45 -121
- data/lib/state_fu/binding.rb +136 -159
- data/lib/state_fu/core_ext.rb +78 -10
- data/lib/state_fu/event.rb +112 -48
- data/lib/state_fu/exceptions.rb +80 -34
- data/lib/state_fu/executioner.rb +149 -0
- data/lib/state_fu/has_options.rb +16 -0
- data/lib/state_fu/hooks.rb +21 -16
- data/lib/state_fu/interface.rb +80 -83
- data/lib/state_fu/lathe.rb +361 -148
- data/lib/state_fu/logger.rb +122 -45
- data/lib/state_fu/machine.rb +60 -32
- data/lib/state_fu/method_factory.rb +180 -72
- data/lib/state_fu/methodical.rb +17 -0
- data/lib/state_fu/persistence/active_record.rb +6 -1
- data/lib/state_fu/persistence/attribute.rb +1 -0
- data/lib/state_fu/persistence/base.rb +8 -6
- data/lib/state_fu/persistence.rb +94 -23
- data/lib/state_fu/sprocket.rb +26 -11
- data/lib/state_fu/state.rb +8 -27
- data/lib/state_fu/transition.rb +207 -98
- data/lib/state_fu/transition_query.rb +214 -0
- data/lib/state_fu.rb +1 -0
- data/lib/tasks/spec_last.rake +46 -0
- data/lib/tasks/state_fu.rake +57 -0
- data/lib/vizier.rb +61 -61
- data/spec/custom_formatter.rb +49 -0
- data/spec/features/binding_and_transition_helper_mixin_spec.rb +2 -2
- data/spec/features/method_missing_only_once_spec.rb +28 -0
- data/spec/features/not_requirements_spec.rb +83 -46
- data/spec/features/plotter_spec.rb +97 -0
- data/spec/features/shared_log_spec.rb +7 -0
- data/spec/features/singleton_machine_spec.rb +39 -0
- data/spec/features/state_and_array_options_accessor_spec.rb +1 -1
- data/spec/features/{transition_boolean_comparison.rb → transition_boolean_comparison_spec.rb} +29 -18
- data/spec/helper.rb +6 -117
- data/spec/integration/active_record_persistence_spec.rb +18 -4
- data/spec/integration/binding_extension_spec.rb +1 -1
- data/spec/integration/class_accessor_spec.rb +49 -59
- data/spec/integration/event_definition_spec.rb +20 -20
- data/spec/integration/example_01_document_spec.rb +13 -8
- data/spec/integration/example_02_string_spec.rb +3 -2
- data/spec/integration/instance_accessor_spec.rb +16 -19
- data/spec/integration/lathe_extension_spec.rb +2 -2
- data/spec/integration/machine_duplication_spec.rb +59 -37
- data/spec/integration/relaxdb_persistence_spec.rb +6 -3
- data/spec/integration/requirement_reflection_spec.rb +66 -57
- data/spec/integration/state_definition_spec.rb +72 -66
- data/spec/integration/transition_spec.rb +169 -173
- data/spec/spec.opts +5 -3
- data/spec/spec_helper.rb +132 -0
- data/spec/state_fu_spec.rb +870 -0
- data/spec/units/binding_spec.rb +33 -22
- data/spec/units/event_spec.rb +3 -22
- data/spec/units/exceptions_spec.rb +7 -0
- data/spec/units/lathe_spec.rb +7 -7
- data/spec/units/machine_spec.rb +67 -75
- data/spec/units/method_factory_spec.rb +55 -48
- data/spec/units/sprocket_spec.rb +5 -7
- data/spec/units/state_spec.rb +33 -24
- metadata +31 -19
- data/lib/state_fu/active_support_lite/inheritable_attributes.rb +0 -1
- data/lib/state_fu/fu_space.rb +0 -51
- data/lib/state_fu/mock_transition.rb +0 -38
- data/spec/BDD/plotter_spec.rb +0 -115
- data/spec/integration/dynamic_requirement_spec.rb +0 -160
- data/spec/integration/ex_machine_for_accounts_spec.rb +0 -79
- data/spec/integration/sanity_spec.rb +0 -31
- data/spec/units/fu_space_spec.rb +0 -95
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../helper")
|
|
2
|
+
|
|
3
|
+
describe "method_missing" do
|
|
4
|
+
include MySpecHelper
|
|
5
|
+
before do
|
|
6
|
+
make_pristine_class('Klass')
|
|
7
|
+
Klass.state_fu_machine() {}
|
|
8
|
+
@obj = Klass.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "should revert to the original method_missing after it is called once" do
|
|
12
|
+
mock.proxy( @obj ).state_fu!.times(1)
|
|
13
|
+
mm1 = @obj.method(:method_missing)
|
|
14
|
+
call_snafu = lambda do
|
|
15
|
+
begin
|
|
16
|
+
@obj.snafu!
|
|
17
|
+
rescue NoMethodError
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
call_snafu.call()
|
|
21
|
+
mm2 = @obj.method(:method_missing)
|
|
22
|
+
mm1.should_not == mm2
|
|
23
|
+
call_snafu.call()
|
|
24
|
+
mm3 = @obj.method(:method_missing)
|
|
25
|
+
mm3.should == mm2
|
|
26
|
+
# @obj.snafu
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -1,81 +1,118 @@
|
|
|
1
1
|
require File.expand_path("#{File.dirname(__FILE__)}/../helper")
|
|
2
2
|
|
|
3
3
|
module RequirementFeatureHelper
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
false
|
|
4
|
+
def account_expired?
|
|
5
|
+
!! account_expired
|
|
7
6
|
end
|
|
8
7
|
|
|
9
|
-
def
|
|
10
|
-
|
|
8
|
+
def valid_password?
|
|
9
|
+
!! valid_password
|
|
11
10
|
end
|
|
11
|
+
end
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
# it_should_behave_like "!" do
|
|
14
|
+
shared_examples_for "not requirements" do
|
|
15
|
+
describe "requirements with names beginning with no[t]_" do
|
|
16
|
+
|
|
17
|
+
it "should return the opposite of the requirement name without not_" do
|
|
18
|
+
# @obj.current_state.should == :guest
|
|
19
|
+
@obj.stfu.teleport! :anonymous
|
|
20
|
+
@obj.valid_password = false
|
|
21
|
+
@binding.can_has_valid_password?.should == false
|
|
22
|
+
@binding.can_has_not_valid_password?.should == true
|
|
23
|
+
@binding.can_has_no_valid_password?.should == true
|
|
24
|
+
@obj.valid_password = true
|
|
25
|
+
@binding.can_has_valid_password?.should == true
|
|
26
|
+
@binding.can_has_not_valid_password?.should == false
|
|
27
|
+
@binding.can_has_no_valid_password?.should == false
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "should call the method directly if one exists" do
|
|
31
|
+
@obj.valid_password = true
|
|
32
|
+
(class << @obj; self; end).class_eval do
|
|
33
|
+
define_method( :no_valid_password? ) { true }
|
|
34
|
+
end
|
|
35
|
+
@binding.can_has_valid_password?.should == true
|
|
36
|
+
@binding.can_has_not_valid_password?.should == false
|
|
37
|
+
@binding.can_has_no_valid_password?.should == true
|
|
38
|
+
end
|
|
16
39
|
|
|
17
|
-
def valid_password?
|
|
18
|
-
!!valid_password_test
|
|
19
40
|
end
|
|
41
|
+
|
|
20
42
|
end
|
|
21
43
|
|
|
22
|
-
describe "
|
|
23
|
-
include MySpecHelper
|
|
44
|
+
describe "requirements" do
|
|
24
45
|
before(:all) do
|
|
25
46
|
reset!
|
|
26
47
|
make_pristine_class('Klass')
|
|
27
|
-
Klass.
|
|
28
|
-
|
|
29
|
-
|
|
48
|
+
Klass.class_eval do
|
|
49
|
+
attr_accessor :valid_password
|
|
50
|
+
attr_accessor :account_expired
|
|
51
|
+
end
|
|
52
|
+
@machine = StateFu::Machine.new do
|
|
30
53
|
initial_state :guest
|
|
31
54
|
|
|
32
|
-
event :
|
|
55
|
+
event :has_valid_password, :from => :anonymous, :to => :logged_in do
|
|
33
56
|
requires :valid_password?
|
|
34
57
|
end
|
|
35
58
|
|
|
36
|
-
event :
|
|
37
|
-
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
state :logged_in do
|
|
41
|
-
requires :not_account_expired?
|
|
59
|
+
event :has_not_valid_password, :from => :anonymous, :to => :suspect do
|
|
60
|
+
requires :not_valid_password?
|
|
42
61
|
end
|
|
43
62
|
|
|
44
|
-
|
|
45
|
-
requires :
|
|
63
|
+
event :has_no_valid_password, :from => :anonymous, :to => :suspect do
|
|
64
|
+
requires :no_valid_password?
|
|
46
65
|
end
|
|
66
|
+
|
|
47
67
|
end
|
|
48
|
-
@obj = Klass.new
|
|
49
|
-
@binding = @obj.state_fu
|
|
50
68
|
end
|
|
51
69
|
|
|
52
|
-
|
|
70
|
+
before :each do
|
|
71
|
+
@obj.valid_password = true
|
|
72
|
+
@obj.account_expired = false
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
describe "requirements defined with a machine helper" do
|
|
76
|
+
before :all do
|
|
77
|
+
@machine.lathe { helper RequirementFeatureHelper }
|
|
78
|
+
@machine.bind!(Klass, :default)
|
|
79
|
+
@obj = Klass.new
|
|
80
|
+
@binding = @obj.state_fu
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it_should_behave_like "not requirements"
|
|
53
84
|
|
|
54
|
-
it "should
|
|
85
|
+
it "should not have methods on the object" do
|
|
86
|
+
@obj.respond_to?(:valid_password?).should == false
|
|
87
|
+
@obj.respond_to?(:account_expired?).should == false
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "should have methods on the binding" do
|
|
91
|
+
# this is a little misleading because theyre not evaluated on the binding ..
|
|
55
92
|
@binding.respond_to?(:valid_password?).should == true
|
|
93
|
+
@binding.respond_to?(:account_expired?).should == true
|
|
56
94
|
@binding.respond_to?(:not_valid_password?).should == false
|
|
57
|
-
@binding.
|
|
58
|
-
@binding.evaluate_named_proc_or_method( :not_valid_password? ).should == false
|
|
95
|
+
@binding.respond_to?(:not_account_expired?).should == false
|
|
59
96
|
end
|
|
97
|
+
end
|
|
60
98
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
@
|
|
64
|
-
@
|
|
99
|
+
describe "requirements defined on the object" do
|
|
100
|
+
before :all do
|
|
101
|
+
@machine.bind!(Klass, :default)
|
|
102
|
+
@obj = Klass.new
|
|
103
|
+
@binding = @obj.state_fu
|
|
104
|
+
Klass.class_eval do
|
|
105
|
+
include RequirementFeatureHelper
|
|
106
|
+
end
|
|
65
107
|
end
|
|
66
108
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
mock( @binding ).valid_password_test.times(2) { true }
|
|
75
|
-
t.unmet_requirements.should == []
|
|
76
|
-
@obj.login_success!(:logged_in).should == true
|
|
77
|
-
@binding.should == :logged_in
|
|
109
|
+
it_should_behave_like "not requirements"
|
|
110
|
+
|
|
111
|
+
it "should have methods on the object" do
|
|
112
|
+
@obj.respond_to?(:valid_password?).should == true
|
|
113
|
+
@obj.respond_to?(:not_valid_password?).should == false
|
|
114
|
+
@obj.respond_to?(:account_expired?).should == true
|
|
115
|
+
@obj.respond_to?(:not_account_expired?).should == false
|
|
78
116
|
end
|
|
79
117
|
end
|
|
80
|
-
|
|
81
118
|
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../helper")
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
##
|
|
5
|
+
##
|
|
6
|
+
|
|
7
|
+
describe StateFu::Plotter do
|
|
8
|
+
include MySpecHelper
|
|
9
|
+
before do
|
|
10
|
+
reset!
|
|
11
|
+
make_pristine_class('Klass')
|
|
12
|
+
@machine = Klass.state_fu_machine(:drawme) do
|
|
13
|
+
chain 'clean -tarnish-> dirty -fester-> putrid'
|
|
14
|
+
end
|
|
15
|
+
@machine = Klass.state_fu_machine(:drawme)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
describe "class methods" do
|
|
20
|
+
describe ".new" do
|
|
21
|
+
it "should expect a StateFu::Machine and return a Plotter" do
|
|
22
|
+
@plotter = StateFu::Plotter.new( @machine )
|
|
23
|
+
@plotter.should be_kind_of(StateFu::Plotter)
|
|
24
|
+
@plotter.machine.should == @machine
|
|
25
|
+
lambda { StateFu::Plotter.new( "abracadabra" ) }.should raise_error(RuntimeError)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe "a new plotter" do
|
|
30
|
+
before do
|
|
31
|
+
@plotter = StateFu::Plotter.new( @machine )
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "should have an empty hash of states" do
|
|
35
|
+
@plotter = StateFu::Plotter.new( @machine )
|
|
36
|
+
@plotter.states.should == {}
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
end # class methods
|
|
41
|
+
|
|
42
|
+
describe "instance methods" do
|
|
43
|
+
before do
|
|
44
|
+
@plotter = StateFu::Plotter.new( @machine )
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
describe ".generate" do
|
|
48
|
+
|
|
49
|
+
it "should call generate_dot!" do
|
|
50
|
+
mock( @plotter ).generate_dot!() { "dot" }
|
|
51
|
+
@plotter.generate
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "should store the result in the dot attribute" do
|
|
55
|
+
mock( @plotter).generate_dot!() { "dot" }
|
|
56
|
+
@plotter.generate
|
|
57
|
+
@plotter.dot.should == "dot"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
describe ".save_as(filename)" do
|
|
61
|
+
it "should save the string to a file" do
|
|
62
|
+
mock( File).open( 'filename', 'w' ).yields( @fh = Object.new() )
|
|
63
|
+
mock( @fh ).write( @plotter.output )
|
|
64
|
+
@plotter.output.save_as( 'filename' )
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
describe ".save!" do
|
|
69
|
+
it "should save the string in a tempfile and return the path" do
|
|
70
|
+
mock(@tempfile = Object.new).path {"path"}.subject
|
|
71
|
+
mock(Tempfile).new(['state_fu_graph','.dot']).yields( @fh = Object.new() ) { @tempfile }
|
|
72
|
+
mock( @fh ).write( @plotter.output )
|
|
73
|
+
@plotter.output.save!.should == 'path'
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end # instance methods
|
|
77
|
+
|
|
78
|
+
describe "output" do
|
|
79
|
+
it "should return the result of .generate" do
|
|
80
|
+
@plotter.output.should == @plotter.generate
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
describe "generate_dot!" do
|
|
85
|
+
it "should return a string" do
|
|
86
|
+
@plotter.generate_dot!.should be_kind_of(String)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it "should extend the string to respond_to save_as" do
|
|
90
|
+
@plotter.output.should respond_to(:save_as)
|
|
91
|
+
end
|
|
92
|
+
end # output
|
|
93
|
+
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../helper")
|
|
2
|
+
|
|
3
|
+
describe "singleton machines" do
|
|
4
|
+
before do
|
|
5
|
+
make_pristine_class('Klass')
|
|
6
|
+
@m = StateFu::Machine.new do
|
|
7
|
+
state :a do
|
|
8
|
+
event :beatify, :transitions_to => :b
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
@m.events.length.should == 1
|
|
12
|
+
@obj = Klass.new
|
|
13
|
+
@m.bind!( @obj, :my_binding)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "should return a binding to the machine when calling the binding's name" do
|
|
17
|
+
@obj.should respond_to(:my_binding)
|
|
18
|
+
@obj.my_binding.should be_kind_of(StateFu::Binding)
|
|
19
|
+
@obj.my_binding.machine.should == @m
|
|
20
|
+
@obj.my_binding.object.should == @obj
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "should have event methods defined" do
|
|
24
|
+
%w/beatify can_beatify? beatify!/.each do |method_name|
|
|
25
|
+
@obj.my_binding.should respond_to(method_name)
|
|
26
|
+
@obj.should respond_to(method_name)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "should transition" do
|
|
31
|
+
@b = @obj.my_binding
|
|
32
|
+
@b.current_state.should == :a
|
|
33
|
+
t = @obj.beatify!
|
|
34
|
+
t.should be_kind_of(StateFu::Transition)
|
|
35
|
+
t.should be_accepted
|
|
36
|
+
@b.current_state.should == :b
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
@@ -8,7 +8,7 @@ describe "extending bindings and transitions with Lathe#helper" do
|
|
|
8
8
|
reset!
|
|
9
9
|
make_pristine_class('Klass')
|
|
10
10
|
|
|
11
|
-
@machine = Klass.
|
|
11
|
+
@machine = Klass.state_fu_machine do
|
|
12
12
|
state :normal, :colour => 'green'
|
|
13
13
|
state :bad, :colour => 'red'
|
|
14
14
|
event( :worsen, :colour => 'orange' ) { from :normal => :bad }
|
data/spec/features/{transition_boolean_comparison.rb → transition_boolean_comparison_spec.rb}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require File.expand_path("#{File.dirname(__FILE__)}/../
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../spec_helper")
|
|
2
2
|
|
|
3
3
|
describe "extending bindings and transitions with Lathe#helper" do
|
|
4
4
|
|
|
@@ -27,40 +27,56 @@ describe "extending bindings and transitions with Lathe#helper" do
|
|
|
27
27
|
#
|
|
28
28
|
|
|
29
29
|
describe StateFu::Transition do
|
|
30
|
-
describe "
|
|
30
|
+
describe "equality" do
|
|
31
|
+
|
|
32
|
+
it "should == the current_state" do
|
|
33
|
+
@transition.should == @transition.current_state
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "should != any other state" do
|
|
37
|
+
@transition.should_not == @transition.target
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "should == the current_state_name" do
|
|
41
|
+
@transition.should == @transition.current_state
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "should != any other State's name" do
|
|
45
|
+
@transition.should_not == @transition.target.name
|
|
46
|
+
end
|
|
31
47
|
|
|
32
48
|
describe "with an unaccepted transition" do
|
|
33
49
|
before do
|
|
34
|
-
stub(@transition).accepted? { false }
|
|
50
|
+
# stub(@transition).accepted? { false }
|
|
35
51
|
end
|
|
36
52
|
|
|
37
|
-
it "should
|
|
53
|
+
it "should != true" do
|
|
38
54
|
@transition.should_not == true
|
|
39
55
|
end
|
|
40
56
|
|
|
41
|
-
it "should
|
|
57
|
+
it "should == false" do
|
|
42
58
|
@transition.should == false
|
|
43
59
|
end
|
|
44
60
|
|
|
45
|
-
it "should === true" do
|
|
61
|
+
it "should not === true" do
|
|
46
62
|
@transition.should_not === true
|
|
47
63
|
end
|
|
48
64
|
|
|
49
|
-
it "should
|
|
65
|
+
it "should === false" do
|
|
50
66
|
@transition.should === false
|
|
51
67
|
end
|
|
52
|
-
|
|
53
|
-
it "should not
|
|
54
|
-
|
|
55
|
-
x = @transition || 1
|
|
56
|
-
x.should == 1
|
|
68
|
+
|
|
69
|
+
it "should not be nil?" do
|
|
70
|
+
@transition.nil?.should be_false
|
|
57
71
|
end
|
|
58
72
|
end
|
|
59
73
|
|
|
60
74
|
|
|
61
75
|
describe "with an accepted transition" do
|
|
62
76
|
before do
|
|
63
|
-
|
|
77
|
+
@obj.ok = true
|
|
78
|
+
@transition.fire!
|
|
79
|
+
@transition.should be_accepted
|
|
64
80
|
end
|
|
65
81
|
it "should == true" do
|
|
66
82
|
@transition.should == true
|
|
@@ -78,11 +94,6 @@ describe "extending bindings and transitions with Lathe#helper" do
|
|
|
78
94
|
@transition.should_not === false
|
|
79
95
|
end
|
|
80
96
|
|
|
81
|
-
it "should evaluate as truthy" do
|
|
82
|
-
x = @transition || 1
|
|
83
|
-
x.should == @transition
|
|
84
|
-
end
|
|
85
|
-
|
|
86
97
|
end
|
|
87
98
|
end
|
|
88
99
|
|
data/spec/helper.rb
CHANGED
|
@@ -1,124 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
-
|
|
2
|
+
require File.join(File.dirname(__FILE__),'spec_helper')
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
StateFu::Logger.suppress!
|
|
10
|
-
|
|
11
|
-
require 'rubygems'
|
|
12
|
-
|
|
13
|
-
{"rr" => "rr", "spec" => "rspec" }.each do |lib, gem_name|
|
|
14
|
-
begin
|
|
15
|
-
require lib
|
|
16
|
-
rescue LoadError => e
|
|
17
|
-
STDERR.puts "The '#{gem_name}' gem is required to run StateFu's specs. Please install it by running (as root):\ngem install #{gem_name}\n\n"
|
|
18
|
-
exit 1;
|
|
19
|
-
end
|
|
4
|
+
begin
|
|
5
|
+
require 'rr'
|
|
6
|
+
rescue LoadError => e
|
|
7
|
+
STDERR.puts "The '#{gem_name}' gem is required to run StateFu's specs. Please install it by running (as root):\ngem install #{gem_name}\n\n"
|
|
8
|
+
exit 1;
|
|
20
9
|
end
|
|
21
10
|
|
|
22
|
-
# require 'state-fu'
|
|
23
|
-
|
|
24
11
|
Spec::Runner.configure do |config|
|
|
25
12
|
config.mock_with :rr
|
|
26
13
|
end
|
|
27
|
-
|
|
28
|
-
module MySpecHelper
|
|
29
|
-
include NoStdout
|
|
30
|
-
|
|
31
|
-
def prepare_active_record( options={}, &migration )
|
|
32
|
-
begin
|
|
33
|
-
require 'activesupport'
|
|
34
|
-
require 'active_record'
|
|
35
|
-
require 'sqlite3'
|
|
36
|
-
rescue LoadError => e
|
|
37
|
-
pending "skipping specifications due to load error: #{e}"
|
|
38
|
-
return false
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
options.symbolize_keys!
|
|
42
|
-
options.assert_valid_keys( :db_config, :migration_name, :hidden )
|
|
43
|
-
|
|
44
|
-
# connect ActiveRecord
|
|
45
|
-
db_config = options.delete(:db_config) || {
|
|
46
|
-
:adapter => 'sqlite3',
|
|
47
|
-
:database => ':memory:'
|
|
48
|
-
}
|
|
49
|
-
ActiveRecord::Base.establish_connection( db_config )
|
|
50
|
-
|
|
51
|
-
return unless block_given?
|
|
52
|
-
|
|
53
|
-
# prepare the migration
|
|
54
|
-
migration_class_name =
|
|
55
|
-
options.delete(:migration_name) || 'BeforeSpecMigration'
|
|
56
|
-
make_pristine_class( migration_class_name, ActiveRecord::Migration )
|
|
57
|
-
migration_class = migration_class_name.constantize
|
|
58
|
-
migration_class.class_eval( &migration )
|
|
59
|
-
|
|
60
|
-
# run the migration without spewing crap everywhere
|
|
61
|
-
if options.delete(:hidden) != false
|
|
62
|
-
no_stdout { migration_class.migrate( :up ) }
|
|
63
|
-
else
|
|
64
|
-
migration_class.migrate( :up )
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def skip_unless_relaxdb
|
|
69
|
-
unless Object.const_defined?( 'RelaxDB' )
|
|
70
|
-
pending('Skipping specs because you do not have the relaxdb gem (paulcarey-relaxdb) installed ...')
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def prepare_relaxdb( options={} )
|
|
75
|
-
begin
|
|
76
|
-
require 'relaxdb'
|
|
77
|
-
if Object.const_defined?( "RelaxDB" )
|
|
78
|
-
RelaxDB.configure :host => "localhost", :port => 5984, :design_doc => "spec_doc"
|
|
79
|
-
RelaxDB.delete_db "relaxdb_spec" rescue "ok"
|
|
80
|
-
RelaxDB.use_db "relaxdb_spec"
|
|
81
|
-
RelaxDB.enable_view_creation
|
|
82
|
-
end
|
|
83
|
-
rescue LoadError => e
|
|
84
|
-
# pending "skipping specifications due to load error: #{e}"
|
|
85
|
-
return false
|
|
86
|
-
end
|
|
87
|
-
begin
|
|
88
|
-
RelaxDB.replicate_db "relaxdb_spec_base", "relaxdb_spec"
|
|
89
|
-
RelaxDB.enable_view_creation
|
|
90
|
-
rescue => e
|
|
91
|
-
puts "\n===== Run rake create_base_db before the first spec run ====="
|
|
92
|
-
puts
|
|
93
|
-
exit!
|
|
94
|
-
end
|
|
95
|
-
#
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def make_pristine_class(class_name, superklass=Object, reset_first = false)
|
|
99
|
-
reset! if reset_first
|
|
100
|
-
@class_names ||= []
|
|
101
|
-
@class_names << class_name
|
|
102
|
-
klass = Class.new( superklass )
|
|
103
|
-
klass.send( :include, StateFu )
|
|
104
|
-
Object.send(:remove_const, class_name ) if Object.const_defined?( class_name )
|
|
105
|
-
Object.const_set(class_name, klass)
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
def reset!
|
|
109
|
-
@class_names ||= []
|
|
110
|
-
@class_names.each do |class_name|
|
|
111
|
-
Object.send(:remove_const, class_name ) if Object.const_defined?( class_name )
|
|
112
|
-
end
|
|
113
|
-
@class_names = []
|
|
114
|
-
StateFu::FuSpace.reset!
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
def set_method_arity( object, method_name, needed_arity = 1 )
|
|
118
|
-
a = Proc.new {}
|
|
119
|
-
stub( a ).arity() { needed_arity }
|
|
120
|
-
stub( object ).method( anything ) { |x| object.send(x) }
|
|
121
|
-
stub( object ).method( method_name ) { a }
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
end
|
|
@@ -30,11 +30,25 @@ describe "an ActiveRecord model with StateFu included:" do
|
|
|
30
30
|
ExampleRecord.superclass.should == ActiveRecord::Base
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
+
describe "when the ActiveRecord model has no table yet (eg before migrations)" do
|
|
34
|
+
before do
|
|
35
|
+
make_pristine_class('TableMissingClass', ActiveRecord::Base )
|
|
36
|
+
TableMissingClass.class_eval do
|
|
37
|
+
state_fu_machine() { }
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "should not raise an error when the persister is instantiated" do
|
|
42
|
+
lambda { TableMissingClass.columns }.should raise_error
|
|
43
|
+
lambda { TableMissingClass.state_fu_machine }.should_not raise_error
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
33
47
|
describe "when the default machine is defined with no field_name specified" do
|
|
34
48
|
before do
|
|
35
49
|
ExampleRecord.class_eval do
|
|
36
|
-
|
|
37
|
-
|
|
50
|
+
state_fu_machine do
|
|
51
|
+
state :initial do
|
|
38
52
|
event( :change, :to => :final ) { after :save! }
|
|
39
53
|
end
|
|
40
54
|
end
|
|
@@ -148,13 +162,13 @@ describe "an ActiveRecord model with StateFu included:" do
|
|
|
148
162
|
r = ExampleRecord.find( @r.id )
|
|
149
163
|
r.state_fu.should be_kind_of( StateFu::Binding )
|
|
150
164
|
r.state_fu.current_state.should be_kind_of( StateFu::State )
|
|
151
|
-
r.state_fu.current_state.should == ExampleRecord.
|
|
165
|
+
r.state_fu.current_state.should == ExampleRecord.state_fu_machine.states[:final]
|
|
152
166
|
end
|
|
153
167
|
end # saved record after transition
|
|
154
168
|
|
|
155
169
|
describe "when a second machine named :status is defined with :field_name => 'status' " do
|
|
156
170
|
before do
|
|
157
|
-
ExampleRecord.
|
|
171
|
+
ExampleRecord.state_fu_machine(:status, :field_name => 'status') do
|
|
158
172
|
event( :go, :from => :initial, :to => :final )
|
|
159
173
|
end
|
|
160
174
|
@ex = ExampleRecord.new()
|