yasm 0.0.2 → 0.0.3

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.markdown CHANGED
@@ -283,6 +283,82 @@ Now, if we create a vending machine, then wait at least a minute, next time we t
283
283
  #==> Yasm::FinalStateException: We're sorry, but the current state `Obliterated` is final. It does not accept any actions.
284
284
 
285
285
 
286
+ ## The Lazy Domino Effect
287
+
288
+ The maximum time limit on a state can cause a domino effect. For example, suppose the start state for your context has a max time limit. And the action that
289
+ runs when that time limit is reached transitions to a state with another max time limit. And so on. Now suppose you instantiate your context, and wait a reeeeealy
290
+ long time. Like, long enough to cause a state transition domino effect. Let's model this with a traffic light system:
291
+
292
+ class TrafficLight
293
+ include Yasm::Context
294
+
295
+ start :green
296
+ end
297
+
298
+ class Green
299
+ include Yasm::State
300
+
301
+ maximum 10.seconds, :action => :transition_to_yellow
302
+ end
303
+
304
+ class TransitionToYellow
305
+ include Yasm::Action
306
+
307
+ triggers :yellow
308
+
309
+ def execute
310
+ puts "transitioning to yellow."
311
+ end
312
+ end
313
+
314
+ class Yellow
315
+ include Yasm::State
316
+
317
+ maximum 3.seconds, :action => :transition_to_red
318
+ end
319
+
320
+ class TransitionToRed
321
+ include Yasm::Action
322
+
323
+ triggers :red
324
+
325
+ def execute
326
+ puts "transitioning to red."
327
+ end
328
+ end
329
+
330
+ class Red
331
+ include Yasm::State
332
+
333
+ maximum 13.seconds, :action => :transition_to_green
334
+ end
335
+
336
+ class TransitionToGreen
337
+ include Yasm::Action
338
+
339
+ triggers :green
340
+
341
+ def execute
342
+ puts "transitioning to green."
343
+ end
344
+ end
345
+
346
+ t = TrafficLight.new
347
+
348
+ puts t.state.value
349
+ #==> Green
350
+
351
+ sleep 30
352
+
353
+ t.state.value
354
+ #==> "transitioning to yellow."
355
+ #==> "transitioning to red."
356
+ #==> "transitioning to green."
357
+ #==> Green
358
+
359
+ Notice that this domino effect happened lazily when you call the `do!` method, or the `context.state.value` methods. Quite nice for systems where
360
+ you persist your state to a db.
361
+
286
362
  ## PUBLIC DOMAIN
287
363
 
288
364
  This software is committed to the public domain. No license. No copyright. DO ANYTHING!
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.2
1
+ 0.0.3
@@ -9,8 +9,13 @@ module Yasm
9
9
  @state = options[:state]
10
10
  end
11
11
 
12
- def value; @state; end
13
-
12
+ def value; state; end
13
+
14
+ def state
15
+ check_maximum
16
+ @state
17
+ end
18
+
14
19
  def state=(s)
15
20
  if s.class == Class
16
21
  @state = s.new
@@ -20,13 +25,51 @@ module Yasm
20
25
  end
21
26
 
22
27
  def do!(*actions)
23
- actions = [self.state.class.maximum_duration_action] + actions if self.state.passed_maximum_time_limit?
28
+ actions.each do |action|
29
+ fire! action
30
+ end
31
+ end
32
+
33
+ private
34
+ def fire!(action)
35
+ check_maximum
24
36
 
25
- Yasm::Manager.execute(
26
- :context => context,
27
- :state_container => self,
28
- :actions => actions
29
- )
37
+ # Verify that the action is possible given the current state
38
+ if !@state.reached_minimum_time_limit?
39
+ raise Yasm::TimeLimitNotYetReached, "We're sorry, but the time limit on the state `#{@state}` has not yet been reached."
40
+ elsif @state.class.final?
41
+ raise Yasm::FinalStateException, "We're sorry, but the current state `#{@state}` is final. It does not accept any actions."
42
+ elsif !@state.class.is_allowed?(action.class)
43
+ raise Yasm::InvalidActionException, "We're sorry, but the action `#{action.class}` is not possible given the current state `#{@state}`."
44
+ end
45
+
46
+ action = Yasm::Manager.setup_action :action => action, :context => context, :state_container => self
47
+ Yasm::Manager.change_state(
48
+ :to => action.class.trigger_state,
49
+ :on => self
50
+ ) if action.class.trigger_state
51
+ Yasm::Manager.execute_action action
52
+ end
53
+
54
+ def check_maximum
55
+ while @state.passed_maximum_time_limit?
56
+ # setup the action that should be performed when a state has lasted too long
57
+ action = Yasm::Manager.setup_action(
58
+ :action => @state.class.maximum_duration_action,
59
+ :context => context,
60
+ :state_container => self
61
+ )
62
+
63
+ # update the state
64
+ Yasm::Manager.change_state(
65
+ :to => action.class.trigger_state || @state.class,
66
+ :on => self,
67
+ :at => @state.instantiated_at + @state.class.maximum_duration
68
+ )
69
+
70
+ # execute the action
71
+ Yasm::Manager.execute_action action
72
+ end
30
73
  end
31
74
  end
32
75
  end
@@ -1,4 +1,3 @@
1
1
  module Yasm
2
- class TimeLimitNotYetReached < RuntimeError
3
- end
2
+ class TimeLimitNotYetReached < RuntimeError; end
4
3
  end
data/lib/yasm/manager.rb CHANGED
@@ -5,40 +5,32 @@ module Yasm
5
5
  def change_state(options)
6
6
  new_state = options[:to]
7
7
  state_container = options[:on]
8
+ state_time = options[:at] || Time.now
8
9
 
9
- raise(
10
- Yasm::TimeLimitNotYetReached,
11
- "We're sorry, but the time limit on the state `#{state_container.state}` has not yet been reached."
12
- ) if state_container.state and !state_container.state.reached_minimum_time_limit?
13
-
14
- new_state = new_state.to_class if new_state.respond_to? :to_class
15
- new_state = new_state.new
16
- new_state.instantiated_at = Time.now
17
-
10
+ new_state = get_instance new_state
11
+ new_state.instantiated_at = state_time
18
12
  state_container.state = new_state
19
13
  end
20
14
 
21
- def execute(options)
15
+ def setup_action(options)
16
+ action = options[:action]
22
17
  context = options[:context]
23
- actions = options[:actions]
24
18
  state_container = options[:state_container]
19
+
20
+ action = get_instance action
21
+ action.context = context
22
+ action.state_container = state_container
23
+ action
24
+ end
25
+
26
+ def execute_action(action)
27
+ action.execute
28
+ end
25
29
 
26
- actions.each do |action|
27
- action = action.new if action.class == Class
28
- action.context = context
29
- action.state_container = state_container
30
-
31
-
32
- # Verify that the action is possible given the current state
33
- if state_container.state.class.final?
34
- raise Yasm::FinalStateException, "We're sorry, but the current state `#{state_container.state}` is final. It does not accept any actions."
35
- elsif !state_container.state.class.is_allowed?(action.class)
36
- raise Yasm::InvalidActionException, "We're sorry, but the action `#{action.class}` is not possible given the current state `#{state_container.state}`."
37
- end
38
-
39
- change_state :to => action.triggers.to_class, :on => state_container if action.triggers
40
- action.execute
41
- end
30
+ def get_instance(obj)
31
+ obj = obj.to_class if obj.respond_to? :to_class
32
+ obj = obj.new if obj.class == Class
33
+ obj
42
34
  end
43
35
  end
44
36
  end
data/yasm.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{yasm}
8
- s.version = "0.0.2"
8
+ s.version = "0.0.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Matt Parker"]
12
- s.date = %q{2011-02-13}
12
+ s.date = %q{2011-02-17}
13
13
  s.description = %q{Breaks up states, actions, and contexts into seperate classes.moonmaster9000@gmail.com}
14
14
  s.email = %q{moonmaster9000@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -39,14 +39,6 @@ Gem::Specification.new do |s|
39
39
  s.require_paths = ["lib"]
40
40
  s.rubygems_version = %q{1.5.0}
41
41
  s.summary = %q{Yet Another State Machine. Pronounced "yaz-um."}
42
- s.test_files = [
43
- "spec/spec_helper.rb",
44
- "spec/yasm/context_spec.rb",
45
- "spec/yasm/conversions_spec.rb",
46
- "spec/yasm/manager_spec.rb",
47
- "spec/yasm/state_container_spec.rb",
48
- "spec/yasm/state_spec.rb"
49
- ]
50
42
 
51
43
  if s.respond_to? :specification_version then
52
44
  s.specification_version = 3
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yasm
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 2
10
- version: 0.0.2
9
+ - 3
10
+ version: 0.0.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Matt Parker
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-02-13 00:00:00 -05:00
18
+ date: 2011-02-17 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -77,12 +77,6 @@ files:
77
77
  - lib/yasm/version.rb
78
78
  - yasm.gemspec
79
79
  - README.markdown
80
- - spec/spec_helper.rb
81
- - spec/yasm/context_spec.rb
82
- - spec/yasm/conversions_spec.rb
83
- - spec/yasm/manager_spec.rb
84
- - spec/yasm/state_container_spec.rb
85
- - spec/yasm/state_spec.rb
86
80
  has_rdoc: true
87
81
  homepage: http://github.com/moonmaster9000/yasm
88
82
  licenses: []
@@ -117,10 +111,5 @@ rubygems_version: 1.5.0
117
111
  signing_key:
118
112
  specification_version: 3
119
113
  summary: Yet Another State Machine. Pronounced "yaz-um."
120
- test_files:
121
- - spec/spec_helper.rb
122
- - spec/yasm/context_spec.rb
123
- - spec/yasm/conversions_spec.rb
124
- - spec/yasm/manager_spec.rb
125
- - spec/yasm/state_container_spec.rb
126
- - spec/yasm/state_spec.rb
114
+ test_files: []
115
+
data/spec/spec_helper.rb DELETED
@@ -1,100 +0,0 @@
1
- $LOAD_PATH.unshift './lib'
2
- require 'yasm'
3
-
4
- # class VendingMachine
5
- # include Yasm::Context
6
- #
7
- # start Waiting
8
- # end
9
- #
10
- # class Waiting
11
- # include Yasm::State
12
- # end
13
- #
14
- # class Vending
15
- # end
16
- #
17
- # class InputMoney
18
- # include Yasm::Action
19
- #
20
- # triggers Vending
21
- # end
22
- #
23
- #
24
- # class VendingMachine
25
- # include Yasm::Context
26
- #
27
- # # start Waiting
28
- # #
29
- # # state :status do
30
- # # start Waiting
31
- # # end
32
- # #
33
- # attr_accessor :money
34
- # def initialize
35
- # @money = 0
36
- # end
37
- # end
38
- #
39
- # class Waiting
40
- # include Yasm::State
41
- #
42
- # actions InputMoney
43
- # end
44
- #
45
- # class Vending
46
- # include Yasm::State
47
- # end
48
- #
49
- # class NotAState
50
- # end
51
- #
52
- # class InputMoney
53
- # include Yasm::Action
54
- # end
55
- #
56
- # class Vend
57
- # include Yasm::Action
58
- # triggers Vending
59
- #
60
- # def initialize(item)
61
- # @item = item
62
- # end
63
- #
64
- # def execute
65
- # puts "Vending #{@item}"
66
- # context.do! Refund if context.money > 0
67
- # end
68
- # end
69
- #
70
- # class Refund
71
- # include Yasm::Action
72
- #
73
- # triggers Waiting
74
- #
75
- # def execute
76
- # puts "Refunding #{context.money}"
77
- # context.money = 0
78
- # end
79
- # end
80
- #
81
- # class MakeSelection
82
- # include Yasm::Action
83
- #
84
- # def initialize(selection)
85
- # @selection = selection
86
- # end
87
- #
88
- # def execute
89
- # if context.money >= selection.price
90
- # trigger Vending
91
- # context.money -= selection.price
92
- # context.do! Vend.new(selection)
93
- # else
94
- # puts "You must enter more money."
95
- # end
96
- # end
97
- # end
98
- #
99
- # class NotAnAction
100
- # end
@@ -1,65 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Yasm::Context do
4
- context "when included in a class" do
5
- before do
6
- class VendingMachine
7
- include Yasm::Context
8
- end
9
-
10
- class Waiting
11
- include Yasm::State
12
- end
13
-
14
- class InputMoney
15
- include Yasm::Action
16
- end
17
- end
18
-
19
- describe "##state" do
20
- it "should require something that can be converted to a symbol" do
21
- proc { VendingMachine.state(nil) }.should raise_exception(ArgumentError, "The state name must respond to `to_sym`")
22
- end
23
-
24
- it "should create a new state configuration" do
25
- VendingMachine.state_configurations[:electricity].should be_nil
26
- class On; include Yasm::State; end
27
- VendingMachine.state(:electricity) { start :on }
28
- VendingMachine.state_configurations[:electricity].should_not be_nil
29
- VendingMachine.state_configurations[:electricity].start_state.should == :on
30
- end
31
-
32
- it "should instance_eval the block on the new state configuration" do
33
- VendingMachine.state_configurations[:power].should be_nil
34
- class On; include Yasm::State; end
35
- VendingMachine.state(:power) { start :on }
36
- VendingMachine.state_configurations[:power].should_not be_nil
37
- VendingMachine.state_configurations[:power].start_state.should == :on
38
- end
39
-
40
- it "should create an instance method that returns the state" do
41
- class On; include Yasm::State; end
42
- VendingMachine.state(:light) { start :on }
43
- VendingMachine.new.light.state.class.should == On
44
- end
45
- end
46
-
47
- describe "##start" do
48
- context "when called directly on the context" do
49
- it "should store the state as the start state of the anonymous state configuration" do
50
- VendingMachine.state_configurations[Yasm::Context::ANONYMOUS_STATE].should be_nil
51
- VendingMachine.start :waiting
52
- VendingMachine.state_configurations[Yasm::Context::ANONYMOUS_STATE].start_state.should == :waiting
53
- end
54
- end
55
- end
56
-
57
- describe "#do!" do
58
- it "should pass all actions passed to it off to the anonymous state_container #do! method" do
59
- v = VendingMachine.new
60
- v.state.should_receive(:do!).with(InputMoney, InputMoney)
61
- v.do! InputMoney, InputMoney
62
- end
63
- end
64
- end
65
- end
@@ -1,43 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Yasm::Conversions::Symbol do
4
- it "should create a :to_class instance method on Symbols" do
5
- :sym.respond_to?(:to_class).should be_true
6
- end
7
- end
8
-
9
- describe Symbol do
10
- describe "#to_class" do
11
- it "should convert the symbol to a class" do
12
- class SymbolTest; end
13
- :symbol_test.to_class.should == SymbolTest
14
- end
15
-
16
- it "should be the inverse of the Class #to_sym class method" do
17
- class SymbolTest; end
18
- :symbol_test.to_class.to_sym.should == :symbol_test
19
- end
20
- end
21
- end
22
-
23
-
24
- describe Yasm::Conversions::Class do
25
- it "should create a :to_sym class method on classes" do
26
- class SymbolTest; end
27
- SymbolTest.respond_to?(:to_sym).should be_true
28
- end
29
- end
30
-
31
- describe Symbol do
32
- describe "#to_sym" do
33
- it "should convert the class to a symbol" do
34
- class SymbolTest; end
35
- SymbolTest.to_sym.should == :symbol_test
36
- end
37
-
38
- it "should be the inverse of the Symbol #to_class instance method" do
39
- class SymbolTest; end
40
- SymbolTest.to_sym.to_class.should == SymbolTest
41
- end
42
- end
43
- end
@@ -1,122 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Yasm::Manager do
4
- before do
5
- class VendingMachine
6
- include Yasm::Context
7
-
8
- start :on
9
- end
10
-
11
- class Unplug
12
- include Yasm::Action
13
-
14
- triggers :off
15
- end
16
-
17
- class PlugIn
18
- include Yasm::Action
19
-
20
- triggers :on
21
- end
22
-
23
- class Destroy
24
- include Yasm::Action
25
-
26
- triggers :destroyed
27
- end
28
-
29
- class On
30
- include Yasm::State
31
-
32
- actions :unplug, :destroy
33
- end
34
-
35
- class Off
36
- include Yasm::State
37
-
38
- actions :plug_in, :destroy
39
- end
40
-
41
- class Destroyed
42
- include Yasm::State
43
-
44
- final!
45
- end
46
-
47
- @vending_machine = VendingMachine.new
48
- end
49
-
50
-
51
-
52
- describe "##change_state" do
53
- it "should convert the state to a class if we pass an object that respond to :to_class" do
54
- Destroyed.should_receive(:to_class).and_return Destroyed
55
- Yasm::Manager.change_state :to => Destroyed, :on => @vending_machine.state
56
- end
57
-
58
- it "should set the instantiated_at property on the state to the current time" do
59
- seconds_since_the_epoch = Time.now
60
- Time.should_receive(:now).twice.and_return seconds_since_the_epoch
61
- Yasm::Manager.change_state :to => On, :on => @vending_machine.state
62
- @vending_machine.state.value.instantiated_at.should == seconds_since_the_epoch
63
- end
64
-
65
- it "should raise an exception if the current state has not yet reached it's time limit" do
66
- class TenSeconds
67
- include Yasm::State
68
-
69
- minimum 10.seconds
70
- end
71
-
72
- proc {
73
- Yasm::Manager.change_state :to => TenSeconds, :on => @vending_machine.state
74
- Yasm::Manager.change_state :to => On, :on => @vending_machine.state
75
- }.should raise_exception(Yasm::TimeLimitNotYetReached, "We're sorry, but the time limit on the state `TenSeconds` has not yet been reached.")
76
- end
77
- end
78
-
79
- describe "##execute" do
80
- it "should apply each action, sequentially, to the appropriate state_container within the context" do
81
- @vending_machine.state.value.class.should == On
82
-
83
- Yasm::Manager.execute :context => @vending_machine, :state_container => @vending_machine.state, :actions => [Unplug]
84
- @vending_machine.state.value.class.should == Off
85
-
86
- Yasm::Manager.execute :context => @vending_machine, :state_container => @vending_machine.state, :actions => [PlugIn]
87
- @vending_machine.state.value.class.should == On
88
- end
89
-
90
- it "should raise an exception if you attempt to execute an action that isn't allowed by a state" do
91
- @vending_machine.state.value.class.should == On
92
-
93
- proc {
94
- Yasm::Manager.execute(
95
- :context => @vending_machine,
96
- :state_container => @vending_machine.state,
97
- :actions => [PlugIn]
98
- )
99
- }.should raise_exception(Yasm::InvalidActionException, "We're sorry, but the action `PlugIn` is not possible given the current state `On`.")
100
- end
101
-
102
- it "should raise an exception if you attempt to execute an action on a final state." do
103
- proc {
104
- Yasm::Manager.execute(
105
- :context => @vending_machine,
106
- :state_container => @vending_machine.state,
107
- :actions => [Destroy, PlugIn]
108
- )
109
- }.should raise_exception(Yasm::FinalStateException, "We're sorry, but the current state `Destroyed` is final. It does not accept any actions.")
110
- end
111
-
112
- it "should not raise an exception if the action is allowed by the state" do
113
- proc {
114
- Yasm::Manager.execute(
115
- :context => @vending_machine,
116
- :state_container => @vending_machine.state,
117
- :actions => [Unplug]
118
- )
119
- }.should_not raise_exception
120
- end
121
- end
122
- end
@@ -1,62 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Yasm::Context::StateContainer do
4
- before do
5
- class VendingMachine
6
- include Yasm::Context
7
-
8
- start :waiting
9
- end
10
-
11
- class Waiting
12
- include Yasm::State
13
- end
14
-
15
- class Hit
16
- include Yasm::Action
17
-
18
- triggers :jammed
19
- end
20
-
21
- class Jammed
22
- include Yasm::State
23
-
24
- maximum 10.seconds, :action => :explode
25
- end
26
-
27
- class Exploded
28
- include Yasm::State
29
-
30
- actions :clean_up
31
- end
32
-
33
- class CleanUp
34
- include Yasm::Action
35
- end
36
-
37
- class Explode
38
- include Yasm::Action
39
- end
40
-
41
- class InputMoney
42
- include Yasm::Action
43
- end
44
- end
45
-
46
- describe "#do!" do
47
- it "should pass the actions off to the Yasm::Manager.execute method" do
48
- v = VendingMachine.new
49
- Yasm::Manager.should_receive(:execute).with(:context => v, :state_container => v.state, :actions => [InputMoney, InputMoney])
50
- v.state.do! InputMoney, InputMoney
51
- end
52
-
53
- it "should add the maximum action to the front of the action list if the maximum time limit has been reached" do
54
- v = VendingMachine.new
55
- v.do! Hit
56
- Yasm::Manager.should_receive(:execute).with(:context => v, :state_container => v.state, :actions => [Explode, CleanUp])
57
- time = 10.seconds.from_now
58
- Time.stub!(:now).and_return time
59
- v.do! CleanUp
60
- end
61
- end
62
- end
@@ -1,110 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Yasm::State do
4
- before do
5
- class TestState
6
- include Yasm::State
7
- end
8
-
9
- class Action1; include Yasm::Action; end
10
- class Action2; include Yasm::Action; end
11
- end
12
-
13
- describe "##actions" do
14
- it "should set the @allowed_actions to the input to this method" do
15
- TestState.actions Action1, Action2
16
- TestState.allowed_actions.should == [Action1, Action2]
17
- end
18
- end
19
-
20
- describe "##final!" do
21
- it "should set the @allowed_actions to an empty array" do
22
- TestState.final!
23
- TestState.allowed_actions.should == []
24
- end
25
- end
26
-
27
- describe "##final?" do
28
- it "should return true if there are no allowed actions" do
29
- TestState.final!
30
- TestState.final?.should be_true
31
- end
32
- end
33
-
34
- describe "##minimum" do
35
- it "should require an integer" do
36
- proc { TestState.minimum "10 minutes" }.should raise_exception("You must provide a Fixnum to the ##minimum method (represents number of seconds). For example: 2.minutes")
37
- end
38
-
39
- it "should set the @state_minimum_duration to the number input" do
40
- TestState.minimum 1.minute
41
- TestState.minimum_duration.should == 60
42
- end
43
- end
44
-
45
- describe "#reached_minimum_time_limit?" do
46
- before do
47
- class MinState
48
- include Yasm::State
49
- end
50
- end
51
-
52
- it "should return true if there is no minimum time limit for the state" do
53
- MinState.new.reached_minimum_time_limit?.should be_true
54
- end
55
-
56
- it "should return false if there is a time limit that hasn't been reached yet" do
57
- MinState.minimum 10.seconds
58
- state = MinState.new
59
- state.instantiated_at = Time.now
60
- state.reached_minimum_time_limit?.should be_false
61
- end
62
-
63
- it "should return true if the state has reached it's time limit" do
64
- MinState.minimum 10.seconds
65
- state = MinState.new
66
- state.instantiated_at = Time.now
67
- ten_seconds_from_now = 10.seconds.from_now
68
- Time.should_receive(:now).and_return ten_seconds_from_now
69
- state.reached_minimum_time_limit?
70
- end
71
- end
72
-
73
- describe "##maximum" do
74
- it "should require both a time limit and an action" do
75
- proc { TestState.maximum }.should raise_exception(ArgumentError)
76
- proc { TestState.maximum 10.seconds }.should raise_exception(ArgumentError)
77
- proc { TestState.maximum 10.seconds, :action => :action1 }.should_not raise_exception
78
- end
79
-
80
- it "should store the time limit and action" do
81
- TestState.maximum 20.seconds, :action => :action2
82
- TestState.maximum_duration.should == 20.seconds
83
- TestState.maximum_duration_action.should == Action2
84
- end
85
- end
86
-
87
- describe "##passed_maximum_time_limit?" do
88
- it "should return false if no time limit has been set" do
89
- class UnlimitedState
90
- include Yasm::State
91
- end
92
-
93
- UnlimitedState.new.passed_maximum_time_limit?.should be_false
94
- end
95
-
96
- it "should return true if a time limit was set, and that limit has been passed" do
97
- class LimitedState
98
- include Yasm::State
99
-
100
- maximum 10.seconds, :action => :action2
101
- end
102
-
103
- s = LimitedState.new
104
- s.instantiated_at = Time.now
105
- ten_seconds_from_now = 10.seconds.from_now
106
- Time.stub!(:now).and_return ten_seconds_from_now
107
- s.passed_maximum_time_limit?.should be_true
108
- end
109
- end
110
- end