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.
Files changed (90) hide show
  1. data/README.textile +124 -34
  2. data/Rakefile +36 -30
  3. data/lib/no_stdout.rb +1 -1
  4. data/lib/state-fu.rb +9 -8
  5. data/lib/state_fu/active_support_lite/array/access.rb +12 -5
  6. data/lib/state_fu/active_support_lite/array/conversions.rb +10 -4
  7. data/lib/state_fu/active_support_lite/array/extract_options.rb +5 -4
  8. data/lib/state_fu/active_support_lite/array/grouping.rb +7 -4
  9. data/lib/state_fu/active_support_lite/array/random_access.rb +4 -3
  10. data/lib/state_fu/active_support_lite/array/wrapper.rb +4 -3
  11. data/lib/state_fu/active_support_lite/array.rb +3 -1
  12. data/lib/state_fu/active_support_lite/blank.rb +18 -9
  13. data/lib/state_fu/active_support_lite/cattr_reader.rb +4 -1
  14. data/lib/state_fu/active_support_lite/keys.rb +8 -3
  15. data/lib/state_fu/active_support_lite/misc.rb +6 -4
  16. data/lib/state_fu/active_support_lite/module/delegation.rb +130 -0
  17. data/lib/state_fu/active_support_lite/module.rb +1 -0
  18. data/lib/state_fu/active_support_lite/object.rb +5 -2
  19. data/lib/state_fu/active_support_lite/string.rb +6 -1
  20. data/lib/state_fu/active_support_lite/symbol.rb +2 -1
  21. data/lib/state_fu/applicable.rb +41 -0
  22. data/lib/state_fu/{helper.rb → arrays.rb} +45 -121
  23. data/lib/state_fu/binding.rb +136 -159
  24. data/lib/state_fu/core_ext.rb +78 -10
  25. data/lib/state_fu/event.rb +112 -48
  26. data/lib/state_fu/exceptions.rb +80 -34
  27. data/lib/state_fu/executioner.rb +149 -0
  28. data/lib/state_fu/has_options.rb +16 -0
  29. data/lib/state_fu/hooks.rb +21 -16
  30. data/lib/state_fu/interface.rb +80 -83
  31. data/lib/state_fu/lathe.rb +361 -148
  32. data/lib/state_fu/logger.rb +122 -45
  33. data/lib/state_fu/machine.rb +60 -32
  34. data/lib/state_fu/method_factory.rb +180 -72
  35. data/lib/state_fu/methodical.rb +17 -0
  36. data/lib/state_fu/persistence/active_record.rb +6 -1
  37. data/lib/state_fu/persistence/attribute.rb +1 -0
  38. data/lib/state_fu/persistence/base.rb +8 -6
  39. data/lib/state_fu/persistence.rb +94 -23
  40. data/lib/state_fu/sprocket.rb +26 -11
  41. data/lib/state_fu/state.rb +8 -27
  42. data/lib/state_fu/transition.rb +207 -98
  43. data/lib/state_fu/transition_query.rb +214 -0
  44. data/lib/state_fu.rb +1 -0
  45. data/lib/tasks/spec_last.rake +46 -0
  46. data/lib/tasks/state_fu.rake +57 -0
  47. data/lib/vizier.rb +61 -61
  48. data/spec/custom_formatter.rb +49 -0
  49. data/spec/features/binding_and_transition_helper_mixin_spec.rb +2 -2
  50. data/spec/features/method_missing_only_once_spec.rb +28 -0
  51. data/spec/features/not_requirements_spec.rb +83 -46
  52. data/spec/features/plotter_spec.rb +97 -0
  53. data/spec/features/shared_log_spec.rb +7 -0
  54. data/spec/features/singleton_machine_spec.rb +39 -0
  55. data/spec/features/state_and_array_options_accessor_spec.rb +1 -1
  56. data/spec/features/{transition_boolean_comparison.rb → transition_boolean_comparison_spec.rb} +29 -18
  57. data/spec/helper.rb +6 -117
  58. data/spec/integration/active_record_persistence_spec.rb +18 -4
  59. data/spec/integration/binding_extension_spec.rb +1 -1
  60. data/spec/integration/class_accessor_spec.rb +49 -59
  61. data/spec/integration/event_definition_spec.rb +20 -20
  62. data/spec/integration/example_01_document_spec.rb +13 -8
  63. data/spec/integration/example_02_string_spec.rb +3 -2
  64. data/spec/integration/instance_accessor_spec.rb +16 -19
  65. data/spec/integration/lathe_extension_spec.rb +2 -2
  66. data/spec/integration/machine_duplication_spec.rb +59 -37
  67. data/spec/integration/relaxdb_persistence_spec.rb +6 -3
  68. data/spec/integration/requirement_reflection_spec.rb +66 -57
  69. data/spec/integration/state_definition_spec.rb +72 -66
  70. data/spec/integration/transition_spec.rb +169 -173
  71. data/spec/spec.opts +5 -3
  72. data/spec/spec_helper.rb +132 -0
  73. data/spec/state_fu_spec.rb +870 -0
  74. data/spec/units/binding_spec.rb +33 -22
  75. data/spec/units/event_spec.rb +3 -22
  76. data/spec/units/exceptions_spec.rb +7 -0
  77. data/spec/units/lathe_spec.rb +7 -7
  78. data/spec/units/machine_spec.rb +67 -75
  79. data/spec/units/method_factory_spec.rb +55 -48
  80. data/spec/units/sprocket_spec.rb +5 -7
  81. data/spec/units/state_spec.rb +33 -24
  82. metadata +31 -19
  83. data/lib/state_fu/active_support_lite/inheritable_attributes.rb +0 -1
  84. data/lib/state_fu/fu_space.rb +0 -51
  85. data/lib/state_fu/mock_transition.rb +0 -38
  86. data/spec/BDD/plotter_spec.rb +0 -115
  87. data/spec/integration/dynamic_requirement_spec.rb +0 -160
  88. data/spec/integration/ex_machine_for_accounts_spec.rb +0 -79
  89. data/spec/integration/sanity_spec.rb +0 -31
  90. 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
- def account_expired_test
6
- false
4
+ def account_expired?
5
+ !! account_expired
7
6
  end
8
7
 
9
- def valid_password_test
10
- true
8
+ def valid_password?
9
+ !! valid_password
11
10
  end
11
+ end
12
12
 
13
- def account_expired?
14
- !!account_expired_test
15
- end
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 "requirement objects" do
23
- include MySpecHelper
44
+ describe "requirements" do
24
45
  before(:all) do
25
46
  reset!
26
47
  make_pristine_class('Klass')
27
- Klass.machine do
28
- helper RequirementFeatureHelper
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 :login_success, :from => :guest, :to => [:logged_in, :expired] do
55
+ event :has_valid_password, :from => :anonymous, :to => :logged_in do
33
56
  requires :valid_password?
34
57
  end
35
58
 
36
- event :login_failure, :from => :guest, :to => :guest do
37
- execute :show_error
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
- state :expired do
45
- requires :account_expired?
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
- describe "requirements with names beginning with not_" do
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 return the opposite of the requirement name without not_" do
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.evaluate_named_proc_or_method( :valid_password? ).should == true
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
- it "should call the method directly if one exists" do
62
- mock( @binding ).not_valid_password?() { true }
63
- @binding.evaluate_named_proc_or_method( :valid_password? ).should == true
64
- @binding.evaluate_named_proc_or_method( :not_valid_password? ).should == true
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
- it "should act as the opposite of requirement in guarding a transition" do
68
- @binding.account_expired?.should == false
69
- @binding.valid_password?.should == true
70
- mock( @binding ).valid_password_test { false }
71
- t = @binding.login_success(:logged_in)
72
- t.requirements.should == [:not_account_expired?, :valid_password?]
73
- t.unmet_requirements.should == [:valid_password?]
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,7 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../helper")
2
+
3
+ describe "using StateFu w/ shared logs" do
4
+ it "should be sane" do
5
+ StateFu::Logger.shared?.should == false
6
+ end
7
+ end
@@ -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.machine do
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 }
@@ -1,4 +1,4 @@
1
- require File.expand_path("#{File.dirname(__FILE__)}/../helper")
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 "#==" do
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 == true" do
53
+ it "should != true" do
38
54
  @transition.should_not == true
39
55
  end
40
56
 
41
- it "should not == false" do
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 not === false" do
65
+ it "should === false" do
50
66
  @transition.should === false
51
67
  end
52
-
53
- it "should not evaluate as truthy" do
54
- pending
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
- stub(@transition).accepted? { true }
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
- thisdir = File.expand_path(File.dirname(__FILE__))
2
+ require File.join(File.dirname(__FILE__),'spec_helper')
3
3
 
4
- # ensure we require state-fu from lib, not gems
5
- $LOAD_PATH.unshift( "#{thisdir}/../lib" )
6
- require 'state-fu'
7
- require 'no_stdout'
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
- machine do
37
- state :initial do
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.machine.states[:final]
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.machine(:status, :field_name => 'status') do
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()
@@ -12,7 +12,7 @@ describe "extending StateFu::Lathe" do
12
12
  before do
13
13
  reset!
14
14
  make_pristine_class('Klass')
15
- @machine = Klass.machine() do
15
+ @machine = Klass.state_fu_machine() do
16
16
  state :init
17
17
  end
18
18
  end # before