state-fu 0.11.1 → 0.12.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,13 +3,12 @@ module StateFu
3
3
 
4
4
  attr_reader :object, :machine, :method_name, :field_name, :persister, :transitions, :options, :target
5
5
 
6
-
7
6
  # the constructor should not be called manually; a binding is
8
7
  # returned when an instance of a class with a StateFu::Machine
9
8
  # calls:
10
9
  #
11
10
  # instance.#state_fu (for the default machine which is called :state_fu),
12
- # instance.#state_fu( :<machine_name> ) ,or
11
+ # instance.#state_fu(:<machine_name>) ,or
13
12
  # instance.#<machine_name>
14
13
  #
15
14
  def initialize( machine, object, method_name, options={} )
@@ -18,13 +17,18 @@ module StateFu
18
17
  @method_name = method_name
19
18
  @transitions = []
20
19
  @options = options.symbolize_keys!
21
- @target = singleton? ? object : object.class
22
- @field_name = options[:field_name] || @target.state_fu_field_names[method_name]
23
- @persister = Persistence.for( self )
20
+ if options[:singleton]
21
+ @target = object
22
+ else
23
+ @target = object.class
24
+ @options = @target.state_fu_options[@method_name].merge(options)
25
+ end
26
+ @field_name = @options.delete(:field_name) || raise("No field_name supplied")
27
+ @persister = Persistence.for self
24
28
 
25
29
  # define event methods on this binding and its @object
26
- MethodFactory.new( self ).install!
27
- @machine.helpers.inject_into( self )
30
+ MethodFactory.new(self).install!
31
+ @machine.helpers.inject_into self
28
32
  end
29
33
 
30
34
  alias_method :o, :object
@@ -2,21 +2,19 @@ module StateFu
2
2
  module Interface
3
3
  module SoftAlias
4
4
 
5
- # define aliases that won't clobber existing methods -
6
- # so we can be liberal with them.
7
- def soft_alias(x)
8
- aliases = [ x.to_a[0] ].flatten
9
- original = aliases.shift
5
+ def soft_alias(hash)
10
6
  existing_method_names = (self.instance_methods | self.protected_instance_methods | self.private_instance_methods).map(&:to_sym)
11
- taken, ok = aliases.partition { |a| existing_method_names.include?(a.to_sym) }
12
- StateFu::Logger.debug("#{self.to_s} alias for ## #{original} already taken: #{taken.inspect}") unless taken.empty?
13
- ok.each { |a| alias_method a, original}
14
- end
15
-
7
+ hash.each do |original, aliases|
8
+ aliases.
9
+ reject { |a| existing_method_names.include?(a.to_sym) }.
10
+ each { |a| alias_method a, original}
11
+ end
12
+ end
16
13
  end
17
14
 
18
15
  module Aliases
19
-
16
+ # define aliases that won't clobber existing methods -
17
+ # so we can be liberal with them.
20
18
  def self.extended(base)
21
19
  base.extend SoftAlias
22
20
  base.class_eval do
@@ -70,8 +68,8 @@ module StateFu
70
68
  end
71
69
  alias_method :machine, :state_fu_machine
72
70
 
73
- def state_fu_field_names
74
- @_state_fu_field_names ||= {}
71
+ def state_fu_options
72
+ @_state_fu_options ||= {}
75
73
  end
76
74
 
77
75
  def state_fu_machines
@@ -97,7 +95,7 @@ module StateFu
97
95
  # can access a StateFu::Machine, the object's current state, the
98
96
  # methods which trigger event transitions, etc.
99
97
 
100
- def state_fu_binding( name = DEFAULT )
98
+ def state_fu_binding(name = DEFAULT)
101
99
  name = name.to_sym
102
100
  if machine = self.class.state_fu_machines[name]
103
101
  state_fu_bindings[name] ||= StateFu::Binding.new( machine, self, name )
@@ -4,7 +4,7 @@ module StateFu
4
4
  def self.BINDINGS
5
5
  @@_bindings ||= {}
6
6
  end
7
-
7
+
8
8
  include Applicable
9
9
  include HasOptions
10
10
 
@@ -17,10 +17,9 @@ module StateFu
17
17
  def self.for_class(klass, name, options={}, &block)
18
18
  options.symbolize_keys!
19
19
  name = name.to_sym
20
-
21
20
  unless machine = klass.state_fu_machines[ name ]
22
21
  machine = new(options)
23
- machine.bind! klass, name, options[:field_name]
22
+ machine.bind! klass, name, options
24
23
  end
25
24
  if block_given?
26
25
  machine.apply! &block
@@ -30,26 +29,36 @@ module StateFu
30
29
 
31
30
  # make it so that a class which has included StateFu has a binding to
32
31
  # this machine
33
- def self.bind!( machine, owner, name, field_name)
32
+ def self.bind!(machine, owner, name, options={})
34
33
  name = name.to_sym
34
+ options[:define_methods] = (name == DEFAULT) unless options.symbolize_keys!.has_key?(:define_methods)
35
+ options[:field_name] ||= Persistence.default_field_name(name)
36
+ options[:singleton] = true unless owner.is_a?(Class)
35
37
  # define an accessor method with the given name
36
- if owner.class == Class
37
- owner.state_fu_machines[name] = machine
38
- owner.state_fu_field_names[name] = field_name
38
+ if options[:singleton]
39
+ _binding = StateFu::Binding.new machine, owner, name, options
40
+ MethodFactory.define_singleton_method(owner, name) { _binding }
41
+ if alias_name = options[:alias] || options[:as]
42
+ MethodFactory.define_singleton_method(owner, alias_name) { _binding }
43
+ end
44
+ else
45
+ owner.state_fu_machines[name] = machine
46
+ owner.state_fu_options[name] = options
39
47
  # method_missing to catch NoMethodError for event methods, etc
40
- StateFu::MethodFactory.define_once_only_method_missing( owner )
41
- unless owner.respond_to?(name)
48
+ StateFu::MethodFactory.define_once_only_method_missing owner
49
+ unless owner.respond_to? name
42
50
  owner.class_eval do
43
51
  define_method name do
44
- state_fu( name )
52
+ state_fu name
53
+ end
54
+ # allow aliases to be set up, e.g. machine(:as => :status)
55
+ if alias_name = options[:alias] || options[:as]
56
+ alias_method alias_name, name
45
57
  end
46
58
  end
47
59
  end
48
60
  # prepare the persistence field
49
- StateFu::Persistence.prepare_field owner, field_name
50
- else
51
- _binding = StateFu::Binding.new machine, owner, name, :field_name => field_name, :singleton => true
52
- MethodFactory.define_singleton_method(owner, name) { _binding }
61
+ StateFu::Persistence.prepare_field owner, options[:field_name]
53
62
  end
54
63
  end
55
64
 
@@ -116,9 +125,8 @@ module StateFu
116
125
 
117
126
  # make it so a class which has included StateFu has a binding to
118
127
  # this machine
119
- def bind!( owner, name= DEFAULT, field_name = nil )
120
- field_name ||= Persistence.default_field_name( name )
121
- self.class.bind!(self, owner, name, field_name)
128
+ def bind!(owner, name=DEFAULT, options={})
129
+ self.class.bind!(self, owner, name, options)
122
130
  end
123
131
 
124
132
  def empty?
@@ -7,14 +7,15 @@ module StateFu
7
7
 
8
8
  class MethodFactory
9
9
  attr_accessor :method_definitions
10
- attr_reader :binding
11
-
10
+ attr_reader :binding, :machine
11
+
12
12
  # An instance of MethodFactory is created to define methods on a specific StateFu::Binding, and
13
13
  # on the object it is bound to.
14
14
 
15
- def initialize( _binding )
16
- @binding = _binding
17
- simple_events, complex_events = @binding.machine.events.partition(&:simple?)
15
+ def initialize(_binding)
16
+ @binding = _binding
17
+ @machine = binding.machine
18
+ simple_events, complex_events = machine.events.partition &:simple?
18
19
  @method_definitions = {}
19
20
 
20
21
  # simple event methods
@@ -95,7 +96,7 @@ module StateFu
95
96
  end unless event.targets.nil?
96
97
  end
97
98
 
98
- @binding.machine.states.each do |state|
99
+ machine.states.each do |state|
99
100
  method_definitions["#{state.name}?"] = lambda do
100
101
  _binding.current_state == state
101
102
  end
@@ -114,9 +115,9 @@ module StateFu
114
115
  # Note this happens when a machine is first bound to the class,
115
116
  # not when StateFu is included.
116
117
 
117
- def self.prepare_class( klass )
118
+ def self.prepare_class(klass)
118
119
  raise caller.inspect
119
- self.define_once_only_method_missing( klass )
120
+ self.define_once_only_method_missing(klass)
120
121
  end # prepare_class
121
122
 
122
123
  # When triggered, method_missing will first call state_fu!,
@@ -137,7 +138,7 @@ module StateFu
137
138
  # or thoroughly understand what's happening in
138
139
  # MethodFactory#define_once_only_method_missing.
139
140
 
140
- def self.define_once_only_method_missing( klass )
141
+ def self.define_once_only_method_missing(klass)
141
142
  raise ArgumentError.new(klass.to_s) unless klass.is_a?(Class)
142
143
 
143
144
  klass.class_eval do
@@ -160,14 +161,14 @@ module StateFu
160
161
  end
161
162
 
162
163
  # call the newly defined method, or the original method_missing
163
- if respond_to?(method_name, true)
164
+ if respond_to? method_name, true
164
165
  # it was defined by calling state_fu!, which instantiated bindings
165
166
  # for its state machines, which defined singleton methods for its
166
167
  # states & events when it was constructed.
167
- __send__( method_name, *args, &block )
168
+ __send__ method_name, *args, &block
168
169
  else
169
170
  # call the original method_missing (method_missing_before_state_fu)
170
- method_missing( method_name, *args, &block )
171
+ method_missing method_name, *args, &block
171
172
  end
172
173
  end # method_missing
173
174
  end # class_eval
@@ -177,8 +178,8 @@ module StateFu
177
178
  # object. Any existing methods will not be tampered with, but a
178
179
  # warning will be issued in the logs if any methods cannot be defined.
179
180
  def install!
180
- define_event_methods_on( @binding )
181
- define_event_methods_on( @binding.object )
181
+ define_event_methods_on @binding
182
+ define_event_methods_on @binding.object if @binding.options[:define_methods]
182
183
  end
183
184
 
184
185
  #
@@ -202,13 +203,13 @@ module StateFu
202
203
  # itself. The remaining arguments are passed into the transition,
203
204
  # as with simple event methods.
204
205
  #
205
- def define_event_methods_on( obj )
206
+ def define_event_methods_on(obj)
206
207
  method_definitions.each do |method_name, method_body|
207
- define_singleton_method( obj, method_name, &method_body)
208
+ define_singleton_method obj, method_name, &method_body
208
209
  end
209
210
  end # define_event_methods_on
210
211
 
211
- def define_singleton_method( object, method_name, &block )
212
+ def define_singleton_method(object, method_name, &block)
212
213
  MethodFactory.define_singleton_method object, method_name, &block
213
214
  end
214
215
 
@@ -221,8 +222,8 @@ module StateFu
221
222
  #
222
223
  # existing methods will never be overwritten.
223
224
 
224
- def self.define_singleton_method( object, method_name, options={}, &block )
225
- if object.respond_to?(method_name, true)
225
+ def self.define_singleton_method(object, method_name, options={}, &block)
226
+ if object.respond_to? method_name, true
226
227
  msg = !options[:force]
227
228
  Logger.info "Existing method #{method(method_name) rescue [method_name].inspect} "\
228
229
  "for #{object.class} #{object} "\
@@ -231,7 +232,7 @@ module StateFu
231
232
  else
232
233
  metaclass = class << object; self; end
233
234
  metaclass.class_eval do
234
- define_method( method_name, &block )
235
+ define_method method_name, &block
235
236
  end
236
237
  end
237
238
  end
@@ -39,7 +39,7 @@ module StateFu
39
39
  end
40
40
 
41
41
  # returns the appropriate persister class for the given class & field name.
42
- def self.class_for( klass, field_name )
42
+ def self.class_for(klass, field_name)
43
43
  raise ArgumentError if [klass, field_name].any?(&:nil?)
44
44
  @@class_for[klass] ||= {}
45
45
  @@class_for[klass][field_name] ||=
@@ -52,7 +52,7 @@ module StateFu
52
52
  end
53
53
  end
54
54
 
55
- def self.for_class( klass, binding, field_name )
55
+ def self.for_class(klass, binding, field_name)
56
56
  persister_class = class_for klass, field_name
57
57
  prepare_field( klass, field_name, persister_class)
58
58
  returning persister_class.new( binding, field_name ) do |persister|
@@ -60,7 +60,7 @@ module StateFu
60
60
  end
61
61
  end
62
62
 
63
- def self.for_instance( binding, field_name )
63
+ def self.for_instance(binding, field_name)
64
64
  metaclass = class << binding.object; self; end
65
65
  for_class( metaclass, binding, field_name )
66
66
  end
@@ -69,7 +69,7 @@ module StateFu
69
69
  # also ensures the persister class method :prepare_field has been called
70
70
  # once for the given class & field name so the field can be set up; eg an
71
71
  # attr_accessor or a before_save hook defined
72
- def self.for( binding )
72
+ def self.for(binding)
73
73
  field_name = binding.field_name.to_sym
74
74
  if binding.singleton?
75
75
  for_instance( binding, field_name )
@@ -95,21 +95,21 @@ module StateFu
95
95
  # checks to see if the field_name for persistence is a
96
96
  # RelaxDB attribute.
97
97
  # Safe to use (skipped) if RelaxDB is not included.
98
- def self.relaxdb_document_property?( klass, field_name )
98
+ def self.relaxdb_document_property?(klass, field_name)
99
99
  Object.const_defined?('RelaxDB') &&
100
100
  klass.ancestors.include?( ::RelaxDB::Document ) &&
101
- klass.properties.map(&:to_s).include?( field_name.to_s )
101
+ klass.properties.map(&:to_s).include?(field_name.to_s)
102
102
  end
103
103
 
104
104
  # checks to see if the field_name for persistence is an
105
105
  # ActiveRecord column.
106
106
  # Safe to use (skipped) if ActiveRecord is not included.
107
- def self.active_record_column?( klass, field_name )
107
+ def self.active_record_column?(klass, field_name)
108
108
  Object.const_defined?("ActiveRecord") &&
109
109
  ::ActiveRecord.const_defined?("Base") &&
110
- klass.ancestors.include?( ::ActiveRecord::Base ) &&
110
+ klass.ancestors.include?(::ActiveRecord::Base) &&
111
111
  klass.table_exists? &&
112
- klass.columns.map(&:name).include?( field_name.to_s )
112
+ klass.columns.map(&:name).include?(field_name.to_s)
113
113
  end
114
114
 
115
115
  end
@@ -1,4 +1,3 @@
1
-
2
1
  require 'logger'
3
2
  module StateFu
4
3
  #
@@ -32,9 +31,9 @@ module StateFu
32
31
  @@shared = false
33
32
  @@log_level = nil
34
33
 
35
- def self.new( logger = $stdout, options={} )
36
- self.suppress = false
37
- self.logger = logger, options
34
+ def self.new( logger=nil, options={} )
35
+ @@suppress = false
36
+ set_logger(logger, options)
38
37
  self
39
38
  end
40
39
 
@@ -55,19 +54,19 @@ module StateFu
55
54
  end
56
55
 
57
56
  def self.shared?
58
- !! @@shared
57
+ !!@@shared
59
58
  end
60
59
 
61
60
  def self.prefix
62
61
  shared? ? @@prefix : nil
63
62
  end
64
63
 
65
- def self.logger= logger
66
- set_logger logger
64
+ def self.logger= new_logger
65
+ set_logger new_logger
67
66
  end
68
67
 
69
68
  def self.instance
70
- @@logger ||= set_logger(Logger.default_logger)
69
+ @@logger ||= default_logger
71
70
  end
72
71
 
73
72
  def self.suppress!
@@ -108,7 +107,7 @@ module StateFu
108
107
  when Logger.activesupport_logger_available? && ActiveSupport::BufferedLogger
109
108
  @@logger = logger
110
109
  else
111
- raise ArgumentError.new
110
+ default_logger
112
111
  end
113
112
  self.shared = !!options.symbolize_keys![:shared]
114
113
  if shared?
@@ -123,27 +122,19 @@ module StateFu
123
122
 
124
123
  private
125
124
 
126
- def self.get_logger( logr = $stdout )
127
- if Object.const_defined?( "RAILS_DEFAULT_LOGGER" )
128
- set_logger RAILS_DEFAULT_LOGGER, :shared => true
129
- else
130
- if Object.const_defined?( 'ActiveSupport' ) && ActiveSupport.const_defined?('BufferedLogger')
131
- set_logger( ActiveSupport::BufferedLogger.new( logr ))
132
- else
133
- set_logger ::Logger.new( logr )
134
- end
135
- end
136
- end
137
-
138
125
  def self.activesupport_logger_available?
139
126
  Object.const_defined?( 'ActiveSupport' ) && ActiveSupport.const_defined?('BufferedLogger')
140
127
  end
141
128
 
142
- def self.default_logger
143
- if Object.const_defined?( "RAILS_DEFAULT_LOGGER" )
144
- RAILS_DEFAULT_LOGGER
145
- else
146
- $stdout
129
+ def self.default_logger(target=$stdout)
130
+ if activesupport_logger_available?
131
+ if Object.const_defined?("RAILS_DEFAULT_LOGGER")
132
+ RAILS_DEFAULT_LOGGER
133
+ else
134
+ ActiveSupport::BufferedLogger.new(target)
135
+ end
136
+ else
137
+ ::Logger.new(target)
147
138
  end
148
139
  end
149
140
 
@@ -156,7 +147,7 @@ module StateFu
156
147
  when nil
157
148
  level
158
149
  else
159
- raise ArgumentError
150
+ raise ArgumentError.new(input.inspect)
160
151
  end
161
152
  end
162
153
 
@@ -0,0 +1,46 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../helper")
2
+
3
+ describe "defining an alias for the default machine" do
4
+ describe "with machine(:as => :status)" do
5
+ before do
6
+ make_pristine_class('Klass')
7
+ Klass.machine :as => :status do
8
+ state :active
9
+ end
10
+ @obj = Klass.new
11
+ end
12
+
13
+ it "should not prevent normal access through #state_fu" do
14
+ @obj.state_fu.machine.should == Klass.machine
15
+ end
16
+
17
+ it "should not affect the internal name of the machine" do
18
+ @obj.status.method_name.should == :default
19
+ end
20
+
21
+ it "should let you access the machine through #status" do
22
+ @obj.status.should be_kind_of(StateFu::Binding)
23
+ @obj.status.machine.should == Klass.machine
24
+ @obj.status.current_state.should == :active
25
+ end
26
+
27
+ end
28
+ end
29
+
30
+ describe "defining an alias for a default singleton machine" do
31
+ describe "with #bind! :default, :as => :alias" do
32
+ before do
33
+ make_pristine_class('Klass')
34
+ @machine = StateFu::Machine.new do
35
+ state :exemplary
36
+ end
37
+ @obj = Klass.new
38
+ @machine.bind!( @obj, :default, :as => :example)
39
+ end
40
+
41
+ it "should work too" do
42
+ @obj.example.machine.should == @machine
43
+ end
44
+ end
45
+ end
46
+
@@ -5,7 +5,7 @@ describe "singleton machines" do
5
5
  make_pristine_class('Klass')
6
6
  @m = StateFu::Machine.new do
7
7
  state :a do
8
- event :beatify, :transitions_to => :b
8
+ event :bify, :transitions_to => :b
9
9
  end
10
10
  end
11
11
  @m.events.length.should == 1
@@ -20,9 +20,22 @@ describe "singleton machines" do
20
20
  @obj.my_binding.object.should == @obj
21
21
  end
22
22
 
23
- it "should have event methods defined" do
24
- %w/beatify can_beatify? beatify!/.each do |method_name|
23
+ it "should have methods defined on the binding by default" do
24
+ %w/bify can_bify? bify!/.each do |method_name|
25
25
  @obj.my_binding.should respond_to(method_name)
26
+ end
27
+ end
28
+
29
+ it "should not have methods defined on the instance by default" do
30
+ %w/bify can_bify? bify!/.each do |method_name|
31
+ @obj.should_not respond_to(method_name)
32
+ end
33
+ end
34
+
35
+
36
+ it "should have methods defined on the instance if bound with :define_methods => true" do
37
+ @m.bind!( @obj, :my_binding, :define_methods => true)
38
+ %w/bify can_bify? bify!/.each do |method_name|
26
39
  @obj.should respond_to(method_name)
27
40
  end
28
41
  end
@@ -30,7 +43,7 @@ describe "singleton machines" do
30
43
  it "should transition" do
31
44
  @b = @obj.my_binding
32
45
  @b.current_state.should == :a
33
- t = @obj.beatify!
46
+ t = @obj.my_binding.bify!
34
47
  t.should be_kind_of(StateFu::Transition)
35
48
  t.should be_accepted
36
49
  @b.current_state.should == :b
@@ -0,0 +1,114 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../helper")
2
+
3
+ describe "instance methods defined for a class's machine," do
4
+ before do
5
+ make_pristine_class('Klass')
6
+ end
7
+
8
+ describe "for the default machine" do
9
+ it "should define methods for states and events" do
10
+ Klass.machine do
11
+ event :go, :from => :a, :to => :b
12
+ end
13
+ instance = Klass.new
14
+ instance.state_fu!
15
+ instance.should respond_to(:a?)
16
+ instance.should respond_to(:can_go?)
17
+ end
18
+
19
+ it "should not define methods given :define_methods => false" do
20
+ Klass.machine :define_methods => false do
21
+ event :go, :from => :a, :to => :b
22
+ end
23
+ instance = Klass.new
24
+ instance.state_fu!
25
+ instance.should_not respond_to(:a?)
26
+ instance.should_not respond_to(:can_go?)
27
+ end
28
+ end
29
+
30
+ describe "for other machines" do
31
+ it "should not define methods" do
32
+ Klass.machine :other do
33
+ event :go, :from => :a, :to => :b
34
+ end
35
+ instance = Klass.new
36
+ instance.state_fu!
37
+ instance.should_not respond_to(:a?)
38
+ instance.should_not respond_to(:can_go?)
39
+ end
40
+
41
+ it "should define methods given :define_methods => true" do
42
+ Klass.machine :define_methods => true do
43
+ event :go, :from => :a, :to => :b
44
+ end
45
+ instance = Klass.new
46
+ instance.state_fu!
47
+ instance.should respond_to(:a?)
48
+ instance.should respond_to(:can_go?)
49
+ end
50
+ end
51
+ end
52
+
53
+
54
+ describe "instance methods when you #bind! a machine" do
55
+ before do
56
+ make_pristine_class('Klass')
57
+ @machine = StateFu::Machine.new do
58
+ state :hot
59
+ state :cold
60
+ end
61
+ end
62
+
63
+ describe "as the default machine," do
64
+ describe "the default behaviour" do
65
+ before do
66
+ @machine.bind! Klass, :default, :define_methods => true
67
+ end
68
+
69
+ it "defines methods" do
70
+ instance = Klass.new
71
+ instance.state_fu!
72
+ instance.should respond_to(:hot?)
73
+ end
74
+ end
75
+
76
+ describe "when it is bound with :define_methods => false" do
77
+ before do
78
+ @machine.bind! Klass, :default, :define_methods => false
79
+ end
80
+
81
+ it "should not define methods" do
82
+ instance = Klass.new
83
+ instance.state_fu!
84
+ instance.should_not respond_to(:hot?)
85
+ end
86
+ end
87
+ end
88
+
89
+ describe "as another machine," do
90
+ describe "the default behaviour" do
91
+ before do
92
+ @machine.bind! Klass, :temperature
93
+ end
94
+
95
+ it "should not define methods" do
96
+ instance = Klass.new
97
+ instance.state_fu!
98
+ instance.should_not respond_to(:hot?)
99
+ end
100
+ end
101
+
102
+ describe "when it is bound with :define_methods => true" do
103
+ before do
104
+ @machine.bind! Klass, :temperature, :define_methods => true
105
+ end
106
+
107
+ it "should define methods" do
108
+ instance = Klass.new
109
+ instance.state_fu!
110
+ instance.should respond_to(:hot?)
111
+ end
112
+ end
113
+ end
114
+ end
@@ -885,7 +885,23 @@ describe "Chameleon" do
885
885
  event :go_inside, :from => {:outside => :inside}
886
886
  end
887
887
 
888
- machine :skin do
888
+ # With :define_methods => true, we can create methods for the :skin
889
+ # machine directly on our Chameleon, so we can type e.g.
890
+ #
891
+ # @chameleon.comoflage! :bark
892
+ # instead of:
893
+ # @chameleon.skin.camoflage! :bark
894
+ #
895
+ # This is the usual behaviour for the default machine, but not for any
896
+ # machine given an explicit name. Otherwise, it would cause confusion
897
+ # when (like the PokerMachine example) multiple machines would compete
898
+ # for the same methods.
899
+ #
900
+ # Hint for the masochistic: state / event methods will never overwrite a
901
+ # pre-existing method, so in the event of overlap, the first machine
902
+ # defined will take precedence.
903
+
904
+ machine :skin, :define_methods => true do
889
905
  initial_state :green
890
906
 
891
907
  states :plaid, :paisley, :tartan, :location => :indoors
@@ -897,9 +913,9 @@ describe "Chameleon" do
897
913
  else
898
914
  case transition.target[:location]
899
915
  when :indoors
900
- inside?
916
+ location.inside?
901
917
  when :outdoors
902
- outside?
918
+ location.outside?
903
919
  else
904
920
  true
905
921
  end
@@ -923,13 +939,13 @@ describe "Chameleon" do
923
939
  @chameleon.current_state(:location).should == :outside
924
940
  @chameleon.current_state(:skin).should == :green
925
941
 
926
- @chameleon.outside?.should == true
942
+ @chameleon.location.outside?.should == true
927
943
 
928
944
  @chameleon.skin.valid_transitions.targets.names.should == [:bark, :pebbles, :foliage]
929
945
  @chameleon.camoflage!(:bark)
930
946
  @chameleon.skin.should == :bark
931
947
 
932
- @chameleon.go_inside!
948
+ @chameleon.location.go_inside!
933
949
  @chameleon.skin.valid_transitions.targets.names.should == [:green, :plaid, :paisley, :tartan]
934
950
 
935
951
  @chameleon.camoflage!(:tartan)
@@ -943,6 +959,7 @@ describe "Chameleon" do
943
959
  end
944
960
 
945
961
  end
962
+
946
963
  end
947
964
 
948
965
 
@@ -14,12 +14,6 @@ describe StateFu::Binding do
14
14
  end
15
15
 
16
16
 
17
- #
18
- #
19
- #
20
-
21
-
22
-
23
17
  #
24
18
  #
25
19
  #
@@ -33,8 +27,10 @@ describe StateFu::Binding do
33
27
 
34
28
  describe "constructor" do
35
29
  before do
36
- mock(Klass).state_fu_field_names.at_most(1) do
37
- { :example => :example_field }
30
+ mock(Klass).state_fu_options.at_most(2) do
31
+ {
32
+ :example => {:field_name => :example_field}
33
+ }
38
34
  end
39
35
  end
40
36
 
@@ -63,10 +59,12 @@ describe StateFu::Binding do
63
59
  end
64
60
 
65
61
  describe "when StateFu::Persistence.active_record_column? is true" do
62
+
66
63
  before do
67
64
  mock( StateFu::Persistence ).active_record_column?(Klass, :example_field).times(1) { true }
68
65
  mock( Klass ).before_create( :state_fu!) { }
69
66
  end
67
+
70
68
  it "should get an ActiveRecord persister" do
71
69
  mock( StateFu::Persistence::ActiveRecord ).new( anything, :example_field ) { @p }
72
70
  b = StateFu::Binding.new( Klass.state_fu_machine, @obj, :example )
@@ -20,22 +20,19 @@ describe StateFu::Machine do
20
20
  before do
21
21
  reset!
22
22
  make_pristine_class 'Klass'
23
- # mock( Klass ).machines() { {} }
24
23
  end
25
24
 
26
25
  it "should create a new machine and bind! it" do
27
26
  @machine = Object.new
28
- mock( @machine ).bind!( Klass, :moose, nil )
29
- mock( StateFu::Machine ).new( {} ) { @machine }
30
- StateFu::Machine.for_class( Klass, :moose )
27
+ mock(@machine).bind!(Klass, :moose, {})
28
+ mock(StateFu::Machine).new({}) { @machine }
29
+ StateFu::Machine.for_class Klass, :moose
31
30
  end
32
31
 
33
32
  it "should apply the block (via lathe) if one is given" do
34
- @m = StateFu::Machine.for_class( Klass, :snoo ) do
33
+ @m = StateFu::Machine.for_class Klass, :snoo do
35
34
  state :porpoise
36
35
  end
37
- # mock( Klass ).machines() { {} }
38
- # @m.states.map(&:name).should == [:porpoise]
39
36
  end
40
37
  end
41
38
 
@@ -85,7 +82,7 @@ describe StateFu::Machine do
85
82
  name = :StinkJuice
86
83
  field_name = 'stink_juice_field'
87
84
  @m.bind!( Klass, name )
88
- Klass.state_fu_field_names[name].should == 'stink_juice_field'
85
+ Klass.state_fu_options[name][:field_name].should == 'stink_juice_field'
89
86
  end
90
87
  end
91
88
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: state-fu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.1
4
+ version: 0.12.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Lee
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-08-26 00:00:00 +10:00
12
+ date: 2009-09-26 00:00:00 +10:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -73,6 +73,7 @@ files:
73
73
  - lib/transition_query.rb
74
74
  - spec/custom_formatter.rb
75
75
  - spec/features/binding_and_transition_helper_mixin_spec.rb
76
+ - spec/features/machine_alias_spec.rb
76
77
  - spec/features/method_missing_only_once_spec.rb
77
78
  - spec/features/not_requirements_spec.rb
78
79
  - spec/features/plotter_spec.rb
@@ -80,6 +81,7 @@ files:
80
81
  - spec/features/singleton_machine_spec.rb
81
82
  - spec/features/state_and_array_options_accessor_spec.rb
82
83
  - spec/features/transition_boolean_comparison_spec.rb
84
+ - spec/features/when_methods_are_defined_spec.rb
83
85
  - spec/helper.rb
84
86
  - spec/integration/active_record_persistence_spec.rb
85
87
  - spec/integration/binding_extension_spec.rb
@@ -138,6 +140,7 @@ summary: A rich library for state-oriented programming with state machines / wor
138
140
  test_files:
139
141
  - spec/custom_formatter.rb
140
142
  - spec/features/binding_and_transition_helper_mixin_spec.rb
143
+ - spec/features/machine_alias_spec.rb
141
144
  - spec/features/method_missing_only_once_spec.rb
142
145
  - spec/features/not_requirements_spec.rb
143
146
  - spec/features/plotter_spec.rb
@@ -145,6 +148,7 @@ test_files:
145
148
  - spec/features/singleton_machine_spec.rb
146
149
  - spec/features/state_and_array_options_accessor_spec.rb
147
150
  - spec/features/transition_boolean_comparison_spec.rb
151
+ - spec/features/when_methods_are_defined_spec.rb
148
152
  - spec/helper.rb
149
153
  - spec/integration/active_record_persistence_spec.rb
150
154
  - spec/integration/binding_extension_spec.rb