davidlee-state-fu 0.0.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.
Files changed (49) hide show
  1. data/LICENSE +40 -0
  2. data/README.textile +174 -0
  3. data/Rakefile +87 -0
  4. data/lib/no_stdout.rb +32 -0
  5. data/lib/state-fu.rb +93 -0
  6. data/lib/state_fu/binding.rb +262 -0
  7. data/lib/state_fu/core_ext.rb +23 -0
  8. data/lib/state_fu/event.rb +98 -0
  9. data/lib/state_fu/exceptions.rb +42 -0
  10. data/lib/state_fu/fu_space.rb +50 -0
  11. data/lib/state_fu/helper.rb +189 -0
  12. data/lib/state_fu/hooks.rb +28 -0
  13. data/lib/state_fu/interface.rb +139 -0
  14. data/lib/state_fu/lathe.rb +247 -0
  15. data/lib/state_fu/logger.rb +10 -0
  16. data/lib/state_fu/machine.rb +159 -0
  17. data/lib/state_fu/method_factory.rb +95 -0
  18. data/lib/state_fu/persistence/active_record.rb +27 -0
  19. data/lib/state_fu/persistence/attribute.rb +46 -0
  20. data/lib/state_fu/persistence/base.rb +98 -0
  21. data/lib/state_fu/persistence/session.rb +7 -0
  22. data/lib/state_fu/persistence.rb +50 -0
  23. data/lib/state_fu/sprocket.rb +27 -0
  24. data/lib/state_fu/state.rb +45 -0
  25. data/lib/state_fu/transition.rb +213 -0
  26. data/spec/helper.rb +86 -0
  27. data/spec/integration/active_record_persistence_spec.rb +189 -0
  28. data/spec/integration/class_accessor_spec.rb +127 -0
  29. data/spec/integration/event_definition_spec.rb +74 -0
  30. data/spec/integration/ex_machine_for_accounts_spec.rb +79 -0
  31. data/spec/integration/example_01_document_spec.rb +127 -0
  32. data/spec/integration/example_02_string_spec.rb +87 -0
  33. data/spec/integration/instance_accessor_spec.rb +100 -0
  34. data/spec/integration/machine_duplication_spec.rb +95 -0
  35. data/spec/integration/requirement_reflection_spec.rb +201 -0
  36. data/spec/integration/sanity_spec.rb +31 -0
  37. data/spec/integration/state_definition_spec.rb +177 -0
  38. data/spec/integration/transition_spec.rb +1060 -0
  39. data/spec/spec.opts +7 -0
  40. data/spec/units/binding_spec.rb +145 -0
  41. data/spec/units/event_spec.rb +232 -0
  42. data/spec/units/exceptions_spec.rb +75 -0
  43. data/spec/units/fu_space_spec.rb +95 -0
  44. data/spec/units/lathe_spec.rb +567 -0
  45. data/spec/units/machine_spec.rb +237 -0
  46. data/spec/units/method_factory_spec.rb +359 -0
  47. data/spec/units/sprocket_spec.rb +71 -0
  48. data/spec/units/state_spec.rb +50 -0
  49. metadata +122 -0
@@ -0,0 +1,127 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../helper")
2
+
3
+ StateFu::FuSpace.reset!
4
+
5
+ ##
6
+ ##
7
+ ##
8
+
9
+ describe "A pristine class Klass with StateFu included:" do
10
+ include MySpecHelper
11
+ before(:each) do
12
+ make_pristine_class 'Klass'
13
+ end
14
+
15
+ it "should return a new Machine bound to the class given Klass.machine()" do
16
+ Klass.should respond_to(:machine)
17
+ Klass.machine.should be_kind_of(StateFu::Machine)
18
+ machine = Klass.machine
19
+ Klass.machine.should == machine
20
+ end
21
+
22
+ it "should return {} given Klass.machines()" do
23
+ Klass.should respond_to(:machines)
24
+ Klass.machines.should == {}
25
+ end
26
+
27
+ it "should return [] given Klass.machine_names()" do
28
+ Klass.should respond_to(:machine_names)
29
+ Klass.machine_names.should == []
30
+ end
31
+
32
+ ##
33
+ ##
34
+ ##
35
+
36
+ describe "Having called Klass.machine() with an empty block:" do
37
+ before(:each) do
38
+ Klass.machine do
39
+ end
40
+ StateFu::DEFAULT_MACHINE.should == :state_fu
41
+ end
42
+
43
+ it "should return a StateFu::Machine given Klass.machine()" do
44
+ Klass.should respond_to(:machine)
45
+ Klass.machine.should_not be_nil
46
+ Klass.machine.should be_kind_of( StateFu::Machine )
47
+ end
48
+
49
+ it "should return { :state_fu => <StateFu::Machine> } given Klass.machines()" do
50
+ Klass.should respond_to(:machines)
51
+ machines = Klass.machines()
52
+ machines.should be_kind_of(Hash)
53
+ machines.should_not be_empty
54
+ machines.length.should == 1
55
+ machines.keys.should == [:state_fu]
56
+ machines.values.first.should be_kind_of( StateFu::Machine )
57
+ end
58
+
59
+ it "should returns [:state_fu] given Klass.machine_names()" do
60
+ Klass.should respond_to(:machine_names)
61
+ Klass.machine_names.should == [:state_fu]
62
+ end
63
+
64
+ describe "Having called Klass.machine(:two) with an empty block:" do
65
+ before(:each) do
66
+ Klass.machine(:two) do
67
+ end
68
+ end
69
+
70
+ it "should return a StateFu::Machine given Klass.machine(:two)" do
71
+ Klass.should respond_to(:machine)
72
+ Klass.machine(:two).should_not be_nil
73
+ Klass.machine(:two).should be_kind_of( StateFu::Machine )
74
+ end
75
+
76
+ it "should return a new Machine given Klass.machine(:three)" do
77
+ Klass.should respond_to(:machine)
78
+ Klass.machine(:three).should be_kind_of( StateFu::Machine )
79
+ three = Klass.machine(:three)
80
+ Klass.machine(:three).should == three
81
+ # StateFu::FuSpace.class_machines[Klass][:three].should == :three
82
+ end
83
+
84
+ it "should return { :state_fu => <StateFu::Machine>, :two => <StateFu::Machine> } given Klass.machines()" do
85
+ Klass.should respond_to(:machines)
86
+ machines = Klass.machines()
87
+ machines.should be_kind_of(Hash)
88
+ machines.should_not be_empty
89
+ machines.length.should == 2
90
+ machines.keys.should include :state_fu
91
+ machines.keys.should include :two
92
+ machines.values.length.should == 2
93
+ machines.values.each { |v| v.should be_kind_of( StateFu::Machine ) }
94
+ end
95
+
96
+ it "should return [:state_fu, :two] give Klass.machine_names (unordered)" do
97
+ Klass.should respond_to(:machine_names)
98
+ Klass.machine_names.length.should == 2
99
+ Klass.machine_names.should include :state_fu
100
+ Klass.machine_names.should include :two
101
+ end
102
+ end
103
+
104
+ describe "An empty class Child which inherits from Klass" do
105
+ before() do
106
+ Object.send(:remove_const, 'Child' ) if Object.const_defined?( 'Child' )
107
+ class Child < Klass
108
+ end
109
+ end
110
+
111
+ # sorry, Lamarckism not supported
112
+ it "does NOT inherit it's parent class' Machines !!" do
113
+ Child.machine.should_not == Klass.machine
114
+ end
115
+
116
+ it "should know the Machine after calling Klass.machine.bind!( Child )" do
117
+ Child.machine.should_not == Klass.machine
118
+ Klass.machine.bind!( Child )
119
+ Child.machine.should == Klass.machine
120
+ Klass.machine.bind!( Child, :snoo )
121
+ Child.machine(:snoo).should == Klass.machine
122
+
123
+ end
124
+
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,74 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../helper")
2
+
3
+ ##
4
+ ##
5
+ ##
6
+
7
+ describe "Adding events to a Machine outside a state block" do
8
+
9
+ include MySpecHelper
10
+
11
+ describe "When there is an empty machine" do
12
+ before do
13
+ reset!
14
+ make_pristine_class 'Klass'
15
+ Klass.machine() { }
16
+ end
17
+
18
+ describe "calling Klass.machine().events" do
19
+ it "should return []" do
20
+ Klass.machine().events.should == []
21
+ end
22
+ end
23
+
24
+ describe "calling event(:die){ from :dead, :to => :alive } in a Klass.machine()" do
25
+ before do
26
+ Klass.machine do
27
+ event :die do # arity == 0
28
+ from :dead, :to => :alive
29
+ end
30
+ end
31
+ end
32
+
33
+ it "should require a name when calling machine.event()" do
34
+ lambda { Klass.machine(){ event {} } }.should raise_error(ArgumentError)
35
+ end
36
+
37
+ it "should add 2 states to the machine called: [:dead, :alive] " do
38
+ Klass.machine.state_names.should == [:dead, :alive]
39
+ Klass.machine.states.length.should == 2
40
+ Klass.machine.states.each { |s| s.should be_kind_of(StateFu::State) }
41
+ Klass.machine.states.map(&:name).sort.should == [:alive, :dead]
42
+ end
43
+
44
+ describe "the <StateFu::Event> created" do
45
+ it "should be accessible through Klass.machine.events" do
46
+ Klass.machine.events.should be_kind_of(Array)
47
+ Klass.machine.events.length.should == 1
48
+ Klass.machine.events.first.should be_kind_of( StateFu::Event )
49
+ Klass.machine.events.first.name.should == :die
50
+ end
51
+ end
52
+
53
+ end
54
+
55
+ # arity of blocks is optional, thanks to magic fairy dust ;)
56
+ describe "calling event(:die){ |s| s.from :dead, :to => :alive } in a Klass.machine()" do
57
+ before do
58
+ Klass.machine do
59
+ event :die do |s|
60
+ s.from :dead, :to => :alive
61
+ end
62
+ end
63
+ end
64
+
65
+ it "should add 2 states to the machine called [:dead, :alive] " do
66
+ Klass.machine.state_names.should == [:dead, :alive]
67
+ Klass.machine.states.length.should == 2
68
+ Klass.machine.states.each { |s| s.should be_kind_of( StateFu::State ) }
69
+ end
70
+ end
71
+
72
+ end
73
+ end
74
+
@@ -0,0 +1,79 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../helper")
2
+
3
+ ##
4
+ ##
5
+ ##
6
+
7
+ describe "A simple Machine definition" do
8
+
9
+ include MySpecHelper
10
+
11
+ describe "When there is a machine describing user logins" do
12
+ before(:all) do
13
+ reset!
14
+ make_pristine_class 'Klass'
15
+
16
+ # TODO
17
+ #
18
+ # Method proxy:
19
+ # @obj.om.helpers[:method_name] => proc
20
+ # look for methods first on obj
21
+ # then in on the helper
22
+ # before raising a method_missing error.
23
+ #
24
+ # when executing methods from the helper,
25
+ # use method(mname) to convert them into something
26
+ # we can instance_eval in the context of our machinist instance :)
27
+ #
28
+ # maybe. or maybe that's just sick.
29
+
30
+ # @machine_spec = lambda do
31
+ Klass.machine( :method_proxy => true ) do
32
+
33
+ states :new, :active, :limbo, :expired, :deleted
34
+
35
+ event :confirm do
36
+ from :new, :to => :confirmed, :auto => true do
37
+ needs :email_confirmation
38
+ end
39
+ end
40
+
41
+ state :confirmed do
42
+ on_entry :send_welcome_email
43
+ end
44
+
45
+ event :login, :from => [:confirmed, :active], :to => :active do
46
+ execute :handle_login do
47
+ halt_unless :password_correct?
48
+ halt_if :dodgy_user_agent?
49
+ obj.generate_new_cookie!
50
+ end
51
+ end
52
+
53
+ state :active do
54
+ on_entry :popup_banner_ads_everywhere
55
+ end
56
+
57
+ event :delete do
58
+ from :ALL, :except => :deleted
59
+ to :deleted
60
+ after do
61
+ obj.destroy!
62
+ end
63
+ end
64
+
65
+ states :ALL do
66
+ accepted(:save!)
67
+ end
68
+
69
+ end
70
+ end # machine
71
+ # end # before
72
+
73
+ # it "parsing it should not throw an error"
74
+ # @machine_spec.should_not raise_error()
75
+ # @machine_spec.call()
76
+
77
+
78
+ end # describe_1
79
+ end
@@ -0,0 +1,127 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../helper")
2
+
3
+ require 'activerecord'
4
+
5
+ describe "Document" do
6
+ include MySpecHelper
7
+ before do
8
+ reset!
9
+ prepare_active_record do
10
+ def self.up
11
+ create_table :documents do |t|
12
+ t.string :name
13
+ t.string :author
14
+ t.string :status_field
15
+ end
16
+ end
17
+ end
18
+ make_pristine_class('Document', ActiveRecord::Base )
19
+ Document.class_eval do
20
+ include StateFu
21
+
22
+ attr_accessor :author
23
+
24
+ def update_rss
25
+ # puts "new feed!"
26
+ end
27
+
28
+ machine( :status ) do
29
+ state :draft do
30
+ event :publish, :to => :published
31
+ end
32
+
33
+ state :published do
34
+ on_entry :update_rss
35
+ requires :author
36
+ end
37
+
38
+ event :delete, :from => :ALL, :to => :deleted do
39
+ execute :destroy
40
+ end
41
+
42
+ events do
43
+ after :save!
44
+ end
45
+ end
46
+ end
47
+
48
+ @doc = Document.new
49
+ # @doc.status
50
+ end
51
+
52
+ describe "a new document with no attributes" do
53
+
54
+ it "should have a status.name of :draft" do
55
+ @doc.status.name.should == :draft
56
+ end
57
+
58
+ it "should have no author" do
59
+ @doc.author.should be_nil
60
+ end
61
+
62
+ it "should raise a RequirementError when publish! is called" do
63
+ lambda { @doc.status.publish! }.should raise_error( StateFu::RequirementError )
64
+ begin
65
+ @doc.status.publish!
66
+ rescue StateFu::RequirementError => e
67
+ e.message.should =~ /[:author]/
68
+ end
69
+ end
70
+ end
71
+
72
+ describe "a new document with an author" do
73
+ before do
74
+ @doc.author = "Susan"
75
+ end
76
+
77
+ it "should have a status.name of :draft" do
78
+ @doc.status.name.should == :draft
79
+ end
80
+
81
+ it "should have an author" do
82
+ @doc.author.should_not be_nil
83
+ end
84
+
85
+ it "should not raise an error when publish! is called" do
86
+ @doc.status.evaluate_requirement(:author).should == "Susan"
87
+ lambda { @doc.status.publish! }.should_not raise_error( )
88
+ end
89
+
90
+ it "should call update_rss when publish! is called" do
91
+ mock( @doc ).update_rss() {}
92
+ @doc.status.publish!
93
+ end
94
+
95
+ it "should have the state name :published after .publish! is called" do
96
+ @doc.status.publish!
97
+ @doc.status.current_state_name.should == :published
98
+ end
99
+
100
+ describe "status_field attribute" do
101
+ it "should be private in ruby 1.8 and 1.9"
102
+
103
+ it "should be defined before state_fu is called" do
104
+ @doc.send( :status_field ).should == 'draft'
105
+ end
106
+
107
+ it "should have an initial value of 'draft'" do
108
+ @doc.instance_eval { status_field }.should == "draft"
109
+ end
110
+
111
+ it "should be set to 'published' after publish! is called successfully" do
112
+ @doc.status.publish!
113
+ @doc.instance_eval { status_field }.should == "published"
114
+ end
115
+ end # status_field
116
+ end # with author
117
+
118
+ describe "delete!" do
119
+
120
+ it "should execute destroy()" do
121
+ mock( @doc ).destroy() {}
122
+ @doc.status.delete!
123
+ end
124
+
125
+ end
126
+
127
+ end
@@ -0,0 +1,87 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../helper")
2
+
3
+ describe String do
4
+ include MySpecHelper
5
+ before do
6
+ reset!
7
+ String.class_eval do
8
+ include StateFu
9
+
10
+ def sanitize_for_shell!
11
+ gsub!(/([\\\t\| &`<>)('"])/) { |s| '\\' << s }
12
+ end
13
+
14
+ def dirty?
15
+ shell.name == :dirty
16
+ end
17
+
18
+ def clean?
19
+ shell.name == :clean
20
+ end
21
+
22
+ def shell_escape!
23
+ shell.escape!
24
+ end
25
+
26
+ def shell_escape
27
+ klone = clone
28
+ begin
29
+ klone.shell.escape!
30
+ rescue StateFu::InvalidTransition
31
+ end
32
+ klone
33
+ end
34
+
35
+ machine (:shell) do
36
+ event(:escape, :from => {:dirty => :clean}) do
37
+ execute :sanitize_for_shell!
38
+ end
39
+ end
40
+ end # String
41
+ @str = "; nohup 'rm -rf /opt' &"
42
+ end # before
43
+
44
+ it "should initially be dirty" do
45
+ @str.dirty?.should be_true
46
+ end
47
+
48
+ it "should call sanitize_for_shell! when shell.escape! is called, and be clean afterwards " do
49
+ @str.should be_dirty
50
+ @str.should_not be_clean
51
+ mock( @str ).sanitize_for_shell! {}
52
+ @str.shell.escape!
53
+ @str.should_not be_dirty
54
+ @str.should be_clean
55
+ end
56
+
57
+ it "should raise an InvalidTransition if shell.escape! is called more than once" do
58
+ @str.shell.escape!
59
+ @str.shell.state_name.should == :clean
60
+
61
+ lambda { @str.shell.escape! }.should raise_error( StateFu::InvalidTransition )
62
+ end
63
+
64
+ it "should modify the string when shell.escape is called" do
65
+ original = @str.dup
66
+ original.should == @str
67
+ @str.shell.escape!
68
+ original.should_not == @str
69
+ end
70
+
71
+ it "should modify the string when shell.escape! is called" do
72
+ original = @str.dup
73
+ original.should == @str
74
+ @str.shell.escape!
75
+ original.should_not == @str
76
+ end
77
+
78
+ it "should not modify the original string when shell_escape() is called" do
79
+ original = @str.dup
80
+ original.should == @str
81
+ clean_copy = @str.shell_escape()
82
+ clean_copy.should be_clean
83
+ @str.should be_dirty
84
+ original.should == @str
85
+ end
86
+
87
+ end
@@ -0,0 +1,100 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../helper")
2
+
3
+ StateFu::FuSpace.reset!
4
+
5
+ ##
6
+ ##
7
+ ##
8
+
9
+ describe "An instance of Klass with StateFu included:" do
10
+ include MySpecHelper
11
+ before(:each) do
12
+ make_pristine_class 'Klass'
13
+ @k = Klass.new()
14
+ end
15
+
16
+ describe "when no machine is defined" do
17
+ it "should return nil given .state_fu()" do
18
+ @k.state_fu().should be_nil
19
+ end
20
+
21
+ it "should return {} given .bindings()" do
22
+ @k.bindings().should == {}
23
+ end
24
+
25
+ it "should return [] given .state_fu!()" do
26
+ @k.state_fu!.should == []
27
+ end
28
+ end # no machine
29
+
30
+ describe "when an empty machine is defined for the class with the default name:" do
31
+ before(:each) do
32
+ Klass.machine() {}
33
+ StateFu::DEFAULT_MACHINE.should == :state_fu
34
+ end
35
+
36
+ it "should return a StateFu::Binding given .state_fu()" do
37
+ @k.state_fu().should be_kind_of( StateFu::Binding )
38
+ end
39
+
40
+ describe "before a binding is instantiated by calling .state_fu() or .state_fu!" do
41
+ it "should return {} given .bindings()" do
42
+ @k.bindings().should == {}
43
+ end
44
+ end
45
+
46
+ describe "after a binding is instantiated with .state_fu()" do
47
+ before do
48
+ @k.state_fu()
49
+ end
50
+
51
+ it "should return { :state_fu => <StateFu::Binding>} given .bindings()" do
52
+ @k.bindings().length.should == 1
53
+ @k.bindings().keys.should == [:state_fu]
54
+ @k.bindings().values.first.should be_kind_of( StateFu::Binding )
55
+ end
56
+ end
57
+
58
+ describe "after .state_fu!()" do
59
+ it "should return { :state_fu => <StateFu::Binding>} given .bindings()" do
60
+ @k.state_fu!()
61
+ @k.bindings().length.should == 1
62
+ @k.bindings().keys.should == [:state_fu]
63
+ @k.bindings().values.first.should be_kind_of( StateFu::Binding )
64
+ end
65
+ end
66
+
67
+ it "should return [<StateFu::Binding>] given .state_fu!()" do
68
+ @k.state_fu!.length.should == 1
69
+ @k.state_fu!.first.should be_kind_of( StateFu::Binding )
70
+ end
71
+
72
+ describe "when there is an empty machine called :two for the class" do
73
+ before(:each) do
74
+ Klass.machine(:two) {}
75
+ end
76
+
77
+ it "should return the same Binding given .state_fu() and .state_fu(:state_fu)" do
78
+ @k.state_fu().should be_kind_of( StateFu::Binding )
79
+ @k.state_fu().should == @k.state_fu(:state_fu)
80
+ end
81
+
82
+ it "should return a StateFu::Binding for the machine called :two given .state_fu(:two)" do
83
+ @k.state_fu(:two).should be_kind_of( StateFu::Binding )
84
+ @k.state_fu(:two).should_not == @k.state_fu(:state_fu)
85
+ @k.state_fu(:two).machine.should == Klass.machine(:two)
86
+ end
87
+
88
+ it "should return nil when .state_fu() is called with the name of a machine which doesn't exist" do
89
+ @k.state_fu(:hibiscus).should be_nil
90
+ end
91
+
92
+ it "should return an array of the two StateFu::Bindings given .state_fu!" do
93
+ @k.state_fu!.should be_kind_of( Array )
94
+ @k.state_fu!.length.should == 2
95
+ @k.state_fu!.each { |m| m.should be_kind_of( StateFu::Binding ) }
96
+ @k.state_fu!.map(&:method_name).sort_by(&:to_s).should == [:state_fu, :two]
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,95 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../helper")
2
+
3
+ ##
4
+ ##
5
+ ##
6
+
7
+ describe "Copying / cloning a Machine" do
8
+
9
+ include MySpecHelper
10
+
11
+ describe "a shallow copy" do
12
+ before do
13
+ reset!
14
+ make_pristine_class("Klass")
15
+ @original = Klass.machine do
16
+ state :a do
17
+ event :goto_b, :to => :b
18
+ end
19
+ end
20
+ @copy = @original.clone
21
+ end
22
+
23
+ it "should update any event in the original when it's changed in the copy" do
24
+ @original.events[:goto_b].should == @copy.events[:goto_b]
25
+ @copy.lathe do
26
+ event :goto_b do |e|
27
+ e.options[:wibble] = :updated
28
+ end
29
+ end
30
+ @copy. events[:goto_b].options[:wibble].should == :updated
31
+ @original.events[:goto_b].options[:wibble].should == :updated
32
+ end
33
+
34
+ it "should update any state in the original when it's changed in the copy" do
35
+ @original.states[:a].should == @copy.states[:a]
36
+ @copy.lathe do
37
+ state :a do |s|
38
+ s.options[:wibble] = :updated
39
+ end
40
+ end
41
+ @copy. states[:a].options[:wibble].should == :updated
42
+ @original.states[:a].options[:wibble].should == :updated
43
+ end
44
+
45
+ it "should update the original with any changes to options"
46
+ it "should update the original with any changes to helpers"
47
+ it "should update the original with any changes to named_procs"
48
+ it "should update the original with any changes to requirement_messages"
49
+
50
+ end # shallow
51
+
52
+ describe "a deep copy" do
53
+ before do
54
+ reset!
55
+ make_pristine_class("Klass")
56
+ @original = Klass.machine do
57
+ state :a do
58
+ event :goto_b, :to => :b
59
+ end
60
+ end
61
+ @copy = @original.deep_clone
62
+ end
63
+
64
+ it "should NOT update any event in the original when it's changed in the copy" do
65
+ pending
66
+ @original.events[:goto_b].should == @copy.events[:goto_b]
67
+ @copy.lathe do
68
+ event :goto_b do |e|
69
+ e.options[:wibble] = :updated
70
+ end
71
+ end
72
+ @copy. events[:goto_b].options[:wibble].should == :updated
73
+ @original.events[:goto_b].options[:wibble].should == nil
74
+ end
75
+
76
+ it "should NOT update any state in the original when it's changed in the copy" do
77
+ pending
78
+ @original.states[:a].should == @copy.states[:a]
79
+ @copy.lathe do
80
+ state :a do |s|
81
+ s.options[:wibble] = :updated
82
+ end
83
+ end
84
+ @copy. states[:a].options[:wibble].should == :updated
85
+ @original.states[:a].options[:wibble].should == nil
86
+ end
87
+
88
+ it "should NOT update the original with any changes to options"
89
+ it "should NOT update the original with any changes to helpers"
90
+ it "should NOT update the original with any changes to named_procs"
91
+ it "should NOT update the original with any changes to requirement_messages"
92
+
93
+ end # deep
94
+
95
+ end