alter-ego 1.0.0 → 1.0.1

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