state-fu 0.11.1 → 0.12.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.
@@ -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