yasm 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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