alter-ego 1.0.0 → 1.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.
@@ -1,3 +1,9 @@
1
+ == 1.0.1 2009-07-19
2
+
3
+ * 2 minor enhancements:
4
+ * Removed dependency on ActiveSupport
5
+ * Removed old internal version of HookR
6
+
1
7
  == 1.0.0 2008-11-28
2
8
 
3
9
  * 1 major enhancement:
@@ -5,8 +5,6 @@ README.rdoc
5
5
  State_Design_Pattern_UML_Class_Diagram.png
6
6
  Rakefile
7
7
  TODO
8
- lib/assertions.rb
9
- spec/assertions_spec.rb
10
8
  lib/alter_ego.rb
11
9
  script/console
12
10
  script/destroy
@@ -14,6 +12,4 @@ script/generate
14
12
  spec/spec.opts
15
13
  spec/spec_helper.rb
16
14
  spec/alter_ego_spec.rb
17
- lib/alter_ego.rb
18
- spec/alter_ego_spec.rb
19
15
  tasks/rspec.rake
data/Rakefile CHANGED
@@ -8,7 +8,8 @@ $hoe = Hoe.new('alter-ego', AlterEgo::VERSION) do |p|
8
8
  p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
9
9
  p.rubyforge_name = p.name # TODO this is default value
10
10
  p.extra_deps = [
11
- ['activesupport','>= 2.0.2'],
11
+ ['fail-fast', '~> 1.1.0'],
12
+ ['hookr', '~> 1.0.0']
12
13
  ]
13
14
  p.extra_dev_deps = [
14
15
  ['newgem', ">= #{::Newgem::VERSION}"]
@@ -29,3 +30,5 @@ Dir['tasks/**/*.rake'].each { |t| load t }
29
30
  task :docs do |task|
30
31
  cp "State_Design_Pattern_UML_Class_Diagram.png", "doc"
31
32
  end
33
+
34
+ task :default => :spec
data/TODO CHANGED
@@ -1,4 +1,6 @@
1
- * TODO Factor assertions out into separate library
1
+ # -*- mode: org -*-
2
+ * DONE Factor assertions out into separate library
3
+ CLOSED: [2008-11-29 Sat 01:29]
2
4
  * TODO Remove ActiveSupport dependency
3
5
  * TODO Nested state support with history
4
6
  * TODO Verify full methods/respond_to? integration
@@ -1,16 +1,19 @@
1
1
  $:.unshift(File.dirname(__FILE__)) unless
2
2
  $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
3
 
4
- require File.join(File.dirname(__FILE__), 'assertions')
4
+ gem 'hookr', "~> 1.0.0"
5
+ gem 'fail-fast', "~> 1.1.0"
6
+
5
7
  require 'forwardable'
6
8
  require 'singleton'
7
9
  require 'rubygems'
8
- require 'activesupport'
10
+ require 'fail_fast'
11
+ require 'hookr'
9
12
 
10
13
  module AlterEgo
11
- VERSION = '1.0.0'
14
+ VERSION = '1.0.1'
12
15
 
13
- include Assertions
16
+ include FailFast::Assertions
14
17
 
15
18
  class StateError < RuntimeError
16
19
  end
@@ -69,12 +72,31 @@ module AlterEgo
69
72
  end
70
73
  end
71
74
 
75
+ # A customization of HookR::Hook to deal with the fact that State internal
76
+ # callbacks need to be executed in the context of the state's context, not the
77
+ # state object itself.
78
+ class StateHook < HookR::Hook
79
+ class StateContextCallback < HookR::InternalCallback
80
+ def call(event)
81
+ context = event.arguments.first
82
+ context.instance_eval(&block)
83
+ end
84
+ end
85
+
86
+ # Add an internal callback that executes in the context of the state
87
+ # context, instead of the state itself
88
+ def add_internal_callback(handle=nil, &block)
89
+ add_block_callback(StateContextCallback, handle, &block)
90
+ end
91
+ end
92
+
72
93
  class State
73
- include Assertions
74
- extend Assertions
94
+ include FailFast::Assertions
95
+ extend FailFast::Assertions
96
+ include HookR::Hooks
75
97
 
76
98
  def self.transition(options, &trans_action)
77
- options.assert_valid_keys(:to, :on, :if)
99
+ assert_only_keys(options, :to, :on, :if)
78
100
  assert_keys(options, :to)
79
101
  guard = options[:if]
80
102
  to_state = options[:to]
@@ -120,14 +142,8 @@ module AlterEgo
120
142
  define_contextual_method_from_symbol_or_block(request, method, &block)
121
143
  end
122
144
 
123
- def self.on_enter(method = nil, &block)
124
- assert(method.nil? ^ block.nil?)
125
- define_contextual_method_from_symbol_or_block(:on_enter, method, &block)
126
- end
127
-
128
- def self.on_exit(method = nil, &block)
129
- assert(method.nil? ^ block.nil?)
130
- define_contextual_method_from_symbol_or_block(:on_exit, method, &block)
145
+ def self.make_hook(name, parent, params)
146
+ ::AlterEgo::StateHook.new(name, parent, params)
131
147
  end
132
148
 
133
149
  def valid_transitions
@@ -164,39 +180,31 @@ module AlterEgo
164
180
  new_state)
165
181
  return false unless continue
166
182
 
167
- if (not valid_transitions.empty?) and (not valid_transitions.include?(new_state))
183
+ unless valid_transitions.empty? || valid_transitions.include?(new_state)
168
184
  raise(InvalidTransitionError,
169
185
  "Not allowed to transition from #{self.identifier} to #{new_state}")
170
186
  end
171
187
 
172
- on_exit(context)
173
- new_state_obj.on_enter(context)
174
- context.state=(new_state)
188
+ execute_hook(:on_exit, context)
189
+ new_state_obj.execute_hook(:on_enter, context)
190
+ context.state = new_state
175
191
  assert(new_state == context.state)
176
192
  true
177
193
  end
178
194
 
179
195
  protected
180
196
 
181
- def on_exit(context)
182
- end
183
-
184
- def on_enter(context)
185
- end
197
+ define_hook :on_enter, :context
198
+ define_hook :on_exit, :context
186
199
 
187
200
  private
188
201
 
189
202
  def self.add_request_filter(request_pattern, new_state_pattern, action)
190
- new_filter = RequestFilter.new(identifier,
191
- request_pattern,
192
- new_state_pattern,
193
- action)
203
+ new_filter = RequestFilter.new(identifier, request_pattern, new_state_pattern, action)
194
204
  self.request_filters << new_filter
195
205
  end
196
206
 
197
- def self.define_contextual_method_from_symbol_or_block(name,
198
- symbol,
199
- &block)
207
+ def self.define_contextual_method_from_symbol_or_block(name, symbol, &block)
200
208
  if symbol
201
209
  define_method(name) do |context, *args|
202
210
  context.send(symbol, *args)
@@ -207,9 +215,11 @@ module AlterEgo
207
215
  end
208
216
  end
209
217
  end
210
- end
218
+ end
211
219
 
212
220
  module ClassMethods
221
+ include FailFast::Assertions
222
+
213
223
  def state(identifier, options={}, &block)
214
224
  if states.has_key?(identifier)
215
225
  raise InvalidDefinitionError, "State #{identifier.inspect} already defined"
@@ -223,7 +233,7 @@ end
223
233
  end
224
234
 
225
235
  def request_filter(options, &block)
226
- options.assert_valid_keys(:state, :request, :new_state, :action)
236
+ assert_only_keys(options, :state, :request, :new_state, :action)
227
237
  options = {
228
238
  :state => not_nil,
229
239
  :request => not_nil,
@@ -250,7 +260,7 @@ end
250
260
  end
251
261
 
252
262
  def add_state(new_state, identifier=new_state.identifier, options = {})
253
- options.assert_valid_keys(:default)
263
+ assert_only_keys(options, :default)
254
264
 
255
265
  self.states[identifier] = new_state.new
256
266
 
@@ -314,7 +324,7 @@ end
314
324
  AlterEgo::NotNilMatcher.instance
315
325
  end
316
326
 
317
- end
327
+ end # End ClassMethods
318
328
 
319
329
  def self.append_features(klass)
320
330
  # Give the other module my instance methods at the class level
@@ -472,7 +472,7 @@ describe TrafficLightWithRedCountdown, "that is yellow" do
472
472
  @it.cycle
473
473
  end
474
474
 
475
- it "should raise an error if #seconds_till_red is called" do
475
+ it "should not raise an error when #seconds_till_red is called" do
476
476
  lambda do
477
477
  @it.seconds_till_red
478
478
  end.should_not raise_error
metadata CHANGED
@@ -1,46 +1,36 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alter-ego
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Avdi Grimm
8
8
  autorequire:
9
9
  bindir: bin
10
- cert_chain:
11
- - |
12
- -----BEGIN CERTIFICATE-----
13
- MIIDKDCCAhCgAwIBAgIBADANBgkqhkiG9w0BAQUFADA6MQ0wCwYDVQQDDARhdmRp
14
- MRQwEgYKCZImiZPyLGQBGRYEYXZkaTETMBEGCgmSJomT8ixkARkWA29yZzAeFw0w
15
- ODExMjYwMzQwMTBaFw0wOTExMjYwMzQwMTBaMDoxDTALBgNVBAMMBGF2ZGkxFDAS
16
- BgoJkiaJk/IsZAEZFgRhdmRpMRMwEQYKCZImiZPyLGQBGRYDb3JnMIIBIjANBgkq
17
- hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxp+TCbzj+cyaiE1xAqxO+irHbdNF+9y4
18
- rZF3gCs0wfIcqeKDIvlks7FvH0Qj6yiAj8YHUgmuLORat2IBLBmX/G+G0Z2L6MLs
19
- bNwx4YpbTW1cwOFVENSWwNjsvY68/I/EpAeRdtiskG/J33TDxi427dyBDSHsrQ8J
20
- 4oC24EnKwsTOdHwkEaDEmZJQeo5ienR7dalAwIPCIm4tA41kbilLVpMVp0f1hn5o
21
- cVFYZgJFOdNnggVO9B/0/doQhxvC4Jdj2XeoOdIkjul1VjCeF+s+i/PhnKk/Y0++
22
- /9fBCqzfFHYay5TOtTLDlzc7WoN5NBtKChn1gG0AnD+mJ4EnjvgTIQIDAQABozkw
23
- NzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUen5OQUuU+3P6OyVZ
24
- NsrtAIO7DQcwDQYJKoZIhvcNAQEFBQADggEBAGwXuO2cpDc9m8iJmmbSjnDhhQYL
25
- OssAG5bMy88JnrD+KufXA4BKvLTLkNtTSaNFvL74+FSIK8VwCUpEyn8rsYi3s6N8
26
- /f5+5LDg19Jm6dmkRgFGQjF8cW0PheDtlY0Ywo+wdUhD+LFH+2VanZNx2dz6IjSh
27
- A0uvcb+roaNG70ESPvoJO4PZFCkrgS2QE9TwnhRLi1DONaGmbMYWSZku4tHFEu+R
28
- B/QQd37jgRGtEcplcoMaoCOqAvlIu6QkQt4X3jVhNGqeF2Wgmb1QXEF8cH/hqX4T
29
- NNbtubu/GbyYwC2cb3Clh5gMrAYS765Q8U2aySfRySAFaQyPub+h0uVWkIc=
30
- -----END CERTIFICATE-----
10
+ cert_chain: []
31
11
 
32
- date: 2008-11-28 00:00:00 -05:00
12
+ date: 2009-07-19 00:00:00 -04:00
33
13
  default_executable:
34
14
  dependencies:
35
15
  - !ruby/object:Gem::Dependency
36
- name: activesupport
16
+ name: fail-fast
37
17
  type: :runtime
38
18
  version_requirement:
39
19
  version_requirements: !ruby/object:Gem::Requirement
40
20
  requirements:
41
- - - ">="
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: 1.1.0
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: hookr
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
42
32
  - !ruby/object:Gem::Version
43
- version: 2.0.2
33
+ version: 1.0.0
44
34
  version:
45
35
  - !ruby/object:Gem::Dependency
46
36
  name: newgem
@@ -50,7 +40,7 @@ dependencies:
50
40
  requirements:
51
41
  - - ">="
52
42
  - !ruby/object:Gem::Version
53
- version: 1.1.0
43
+ version: 1.3.0
54
44
  version:
55
45
  - !ruby/object:Gem::Dependency
56
46
  name: hoe
@@ -82,8 +72,6 @@ files:
82
72
  - State_Design_Pattern_UML_Class_Diagram.png
83
73
  - Rakefile
84
74
  - TODO
85
- - lib/assertions.rb
86
- - spec/assertions_spec.rb
87
75
  - lib/alter_ego.rb
88
76
  - script/console
89
77
  - script/destroy
@@ -115,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
115
103
  requirements: []
116
104
 
117
105
  rubyforge_project: alter-ego
118
- rubygems_version: 1.2.0
106
+ rubygems_version: 1.3.1
119
107
  signing_key:
120
108
  specification_version: 2
121
109
  summary: AlterEgo is a Ruby implementation of the State pattern as described by the Gang of Four
data.tar.gz.sig DELETED
Binary file
@@ -1,63 +0,0 @@
1
- class AssertionFailureError < Exception
2
- end
3
-
4
- module Assertions
5
-
6
- # Assert that no +values+ are nil or false. Returns the last value.
7
- def assert(*values, &block)
8
- iterate_and_return_last(values, block) do |v|
9
- raise_assertion_error unless v
10
- end
11
- end
12
-
13
- # The opposite of #assert.
14
- def deny(*values)
15
- assert(*values.map{ |v| !v})
16
- assert(yield(*values)) if block_given?
17
- values.last
18
- end
19
-
20
- # Assert that no +values+ are nil. Returns the last value.
21
- def assert_exists(*values, &block)
22
- iterate_and_return_last(values, block) { |value| deny(value.nil?) }
23
- end
24
-
25
- # Assert that +values+ are collections that contain at least one element.
26
- # Returns the last value.
27
- def assert_one_or_more(*values, &block)
28
- iterate_and_return_last(values, block) do |value|
29
- assert_exists(value)
30
- deny(value.kind_of?(String))
31
- deny(value.empty?)
32
- end
33
- end
34
-
35
- def assert_keys(hash, *keys)
36
- assert_exists(hash)
37
- assert(hash.respond_to?(:[]))
38
- values = keys.inject([]) { |vals, k| vals << assert_exists(hash[k]) }
39
- assert(yield(*values)) if block_given?
40
- hash
41
- end
42
-
43
- private
44
-
45
- def iterate_and_return_last(values, block = nil)
46
- values.each { |v| yield(v) }
47
- if block
48
- raise_assertion_error unless block.call(*values)
49
- end
50
- values.last
51
- end
52
-
53
- def raise_assertion_error
54
- error = AssertionFailureError.new
55
- backtrace = caller
56
- trimmed_backtrace = []
57
- trimmed_backtrace.unshift(backtrace.pop) until
58
- backtrace.last.include?(__FILE__)
59
- error.set_backtrace(trimmed_backtrace)
60
- raise error
61
- end
62
-
63
- end
@@ -1,284 +0,0 @@
1
- require File.expand_path('spec_helper', File.dirname(__FILE__))
2
-
3
- module AssertionsSpecHelper
4
- def do_success(&block)
5
- do_assertion(@success_values.first, &block)
6
- end
7
- def do_failure(&block)
8
- do_assertion(@failure_values.first, &block)
9
- end
10
- end
11
-
12
- describe "any assertion", :shared => true do
13
- it "on failure, should raise an exception with trimmed backtrace" do
14
- begin
15
- do_failure
16
- rescue AssertionFailureError => e
17
- e.backtrace.first.should include(__FILE__)
18
- end
19
- end
20
- end
21
-
22
- describe "a basic assertion", :shared => true do
23
- it "should raise AssertionFailureError when it fails" do
24
- @failure_values.each do |value|
25
- lambda do
26
- do_assertion(value)
27
- end.should raise_error(AssertionFailureError)
28
- end
29
- end
30
-
31
- it "should not raise an exception when it succeeds" do
32
- @success_values.each do |value|
33
- lambda do
34
- do_assertion(value)
35
- end.should_not raise_error
36
- end
37
- end
38
-
39
- it "should return its argument on success" do
40
- @success_values.each do |value|
41
- do_assertion(value).should equal(value)
42
- end
43
- end
44
-
45
- end
46
-
47
- describe "an assertion taking a block", :shared => true do
48
- it "should fail if the block result is not true" do
49
- lambda do
50
- do_success { false }
51
- end.should raise_error(AssertionFailureError)
52
- end
53
- end
54
-
55
- describe "an assertion yielding passed values", :shared => true do
56
-
57
- it_should_behave_like "an assertion taking a block"
58
-
59
- it "should yield values that pass the test" do
60
- @success_values.each do |value|
61
- did_yield = false
62
- do_assertion(value) do |yielded_value|
63
- did_yield = true
64
- yielded_value.should equal(value)
65
- true
66
- end
67
- did_yield.should be_true
68
- end
69
- end
70
-
71
- it "should not yield values that fail the test" do
72
- @failure_values.each do |value|
73
- did_yield = false
74
- lambda do
75
- do_assertion(value) do |yielded_value|
76
- did_yield = true
77
- end
78
- end.should raise_error(AssertionFailureError)
79
- did_yield.should be_false
80
- end
81
- end
82
-
83
- end
84
-
85
- describe "an assertion taking multiple values", :shared => true do
86
- def gather_arguments(values)
87
- args = []
88
- # gather 3 arguments
89
- 3.times do |i|
90
- args[i] = values[i % values.size]
91
- end
92
- args
93
- end
94
-
95
- it "should not raise error if all values succeed test" do
96
- values = gather_arguments(@success_values)
97
- lambda { do_assertion(*values) }.should_not raise_error
98
- end
99
-
100
- it "should raise error if all values fail test" do
101
- values = gather_arguments(@failure_values)
102
- lambda { do_assertion(*values) }.should raise_error(AssertionFailureError)
103
- end
104
-
105
- it "should raise error if one values fails test" do
106
- values = gather_arguments(@success_values)
107
- values[1] = @failure_values.first
108
- lambda { do_assertion(*values) }.should raise_error(AssertionFailureError)
109
- end
110
-
111
- it "should return the last argument on success" do
112
- values = gather_arguments(@success_values)
113
- do_assertion(*values).should equal(values.last)
114
- end
115
-
116
- end
117
-
118
- describe Assertions, "#assert" do
119
-
120
- include Assertions
121
- include AssertionsSpecHelper
122
-
123
- def do_assertion(*args, &block)
124
- assert(*args, &block)
125
- end
126
-
127
- before :each do
128
- @success_values = [true, "", 0]
129
- @failure_values = [false, nil]
130
- end
131
-
132
- it_should_behave_like "any assertion"
133
- it_should_behave_like "a basic assertion"
134
- it_should_behave_like "an assertion taking multiple values"
135
- it_should_behave_like "an assertion yielding passed values"
136
- end
137
-
138
- describe Assertions, "#assert_exists" do
139
-
140
- include Assertions
141
- include AssertionsSpecHelper
142
-
143
- def do_assertion(*args, &block)
144
- assert_exists(*args, &block)
145
- end
146
-
147
- before :each do
148
- @success_values = ["foo", 123, false]
149
- @failure_values = [nil]
150
- end
151
-
152
- it_should_behave_like "any assertion"
153
- it_should_behave_like "a basic assertion"
154
- it_should_behave_like "an assertion taking multiple values"
155
- it_should_behave_like "an assertion yielding passed values"
156
-
157
- end
158
-
159
- describe Assertions, "#assert_one_or_more" do
160
-
161
- include Assertions
162
- include AssertionsSpecHelper
163
-
164
- def do_assertion(*args, &block)
165
- assert_one_or_more(*args, &block)
166
- end
167
-
168
- before :each do
169
- @success_values = [[1], {:foo => :bar }]
170
- @failure_values = [nil, [], "foo"]
171
- end
172
-
173
- it_should_behave_like "any assertion"
174
- it_should_behave_like "a basic assertion"
175
- it_should_behave_like "an assertion taking multiple values"
176
- it_should_behave_like "an assertion yielding passed values"
177
- end
178
-
179
- describe Assertions, "#deny" do
180
-
181
- include Assertions
182
- include AssertionsSpecHelper
183
-
184
- def do_assertion(*args, &block)
185
- deny(*args, &block)
186
- end
187
-
188
- before :each do
189
- @success_values = [false, nil]
190
- @failure_values = [true, "", 0]
191
- end
192
-
193
- it_should_behave_like "any assertion"
194
- it_should_behave_like "a basic assertion"
195
- it_should_behave_like "an assertion taking multiple values"
196
- it_should_behave_like "an assertion yielding passed values"
197
- end
198
-
199
- describe Assertions, "#assert_keys" do
200
-
201
- include Assertions
202
-
203
- def do_assertion(*args, &block)
204
- assert_keys(*args, &block)
205
- end
206
-
207
- def do_success(&block)
208
- assert_keys({}, &block)
209
- end
210
-
211
- def do_failure(&block)
212
- assert_keys({}, :foo, &block)
213
- end
214
-
215
- it_should_behave_like "any assertion"
216
- it_should_behave_like "an assertion taking a block"
217
-
218
- it "should fail if a specified key does not exist" do
219
- lambda { assert_keys({}, :foo) }.should raise_error(AssertionFailureError)
220
- end
221
-
222
- it "should fail if a specified key is nil" do
223
- lambda do
224
- assert_keys({:foo => nil}, :foo)
225
- end.should raise_error(AssertionFailureError)
226
- end
227
-
228
- it "should fail if any of the specified keys are nil" do
229
- lambda do
230
- assert_keys({:foo => true, :bar => nil}, :foo, :bar)
231
- end.should raise_error(AssertionFailureError)
232
- end
233
-
234
- it "should fail if the given hash is nil" do
235
- lambda do
236
- assert_keys(nil)
237
- end.should raise_error(AssertionFailureError)
238
- end
239
-
240
- it "should fail if given something unlike a hash" do
241
- lambda do
242
- assert_keys(true)
243
- end.should raise_error(AssertionFailureError)
244
- end
245
-
246
- it "should succeed if no keys are given" do
247
- lambda do
248
- assert_keys({:foo => true, :bar => nil})
249
- end.should_not raise_error
250
- end
251
-
252
- it "should yield key values if they all exist" do
253
- did_yield = false
254
- assert_keys({:foo => 23, :bar => 32}, :foo, :bar) do |x, y|
255
- did_yield = true
256
- x.should == 23
257
- y.should == 32
258
- true
259
- end
260
- did_yield.should be_true
261
- end
262
-
263
- it "should yield nothing if a key is missing" do
264
- begin
265
- did_yield = false
266
- assert_keys({:foo => 23, :bar => 32}, :foo, :bar) do |x, y|
267
- did_yield = true
268
- end
269
- rescue AssertionFailureError
270
- did_yield.should be_false
271
- end
272
- end
273
-
274
- it "should return the hash" do
275
- @hash = { :buz => 42 }
276
- assert_keys(@hash, :buz).should equal(@hash)
277
- end
278
- end
279
-
280
- describe AssertionFailureError do
281
- it "should derive from Exception" do
282
- AssertionFailureError.superclass.should equal(Exception)
283
- end
284
- end
metadata.gz.sig DELETED
@@ -1,2 +0,0 @@
1
- �?(��(��y�c.�#�~�Z��+�p��8���!W�J!S���N"�t>4]��-��g��xG�=�F\
2
- Y�ɏ�m�(�;���.��>e"���>O