Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Incorrect super call in state-bound methods #196

Closed
the8472 opened this Issue · 3 comments

3 participants

@the8472
class MyClass
  state_machine do
    state :my_state do
      def my_method
      end
    end
  end
end

obj = MyClass.new
obj.state = :some_other_state
obj.my_method if obj.respond_to? :my_method

This results in an exception that super is not found

The cause is in state.rb#L199 where you do

self.class.state_machine(#{machine_name.inspect}).states.fetch(#{name.inspect}).call(self, #{method.inspect}, lambda {super(*args, &block)}, *args, &block)

Which means the method itself is still defined (causing the respond_to? to succeed) which then calls super, which fails.

@jturkel

This bug also means that you can't define the behavior of methods in different states e.g.

class MyClass
  extend StateMachine::MacroMethods

  state_machine :state, :initial => :my_state do
    state :my_state do
      def my_method
        puts "Hello from my_state"
      end
    end

    state :my_other_state do
      def my_method
        puts "Hello from my_other_state"
      end
    end
  end

end

obj = MyClass.new
obj.state = :my_other_state
obj.my_method

This results in the following exception:

NoMethodError: super: no superclass method `my_method' for #<MyClass:0x007fd293ade928 @state=:my_other_state>
    from /Users/jturkel/.rvm/gems/ruby-1.9.3-p362@dandelion/gems/state_machine-1.1.2/lib/state_machine/state.rb:193:in `block in my_method'
    from /Users/jturkel/.rvm/gems/ruby-1.9.3-p362@dandelion/gems/state_machine-1.1.2/lib/state_machine/state.rb:217:in `call'
    from /Users/jturkel/.rvm/gems/ruby-1.9.3-p362@dandelion/gems/state_machine-1.1.2/lib/state_machine/state.rb:217:in `call'
    from /Users/jturkel/.rvm/gems/ruby-1.9.3-p362@dandelion/gems/state_machine-1.1.2/lib/state_machine/state.rb:193:in `my_method'
    from /Users/jturkel/.rvm/gems/ruby-1.9.3-p362@dandelion/gems/state_machine-1.1.2/lib/state_machine/state.rb:193:in `block in my_method'
    from /Users/jturkel/.rvm/gems/ruby-1.9.3-p362@dandelion/gems/state_machine-1.1.2/lib/state_machine/state.rb:217:in `call'
    from /Users/jturkel/.rvm/gems/ruby-1.9.3-p362@dandelion/gems/state_machine-1.1.2/lib/state_machine/state.rb:217:in `call'
    from /Users/jturkel/.rvm/gems/ruby-1.9.3-p362@dandelion/gems/state_machine-1.1.2/lib/state_machine/state.rb:193:in `my_method'
@jturkel

Doh. Ignore my comment above. Looks like it works if you use a string not a symbol for the state name i.e. the following works:

obj.state = 'my_other_state'
@obrie obrie closed this in feff2a5
@obrie
Owner

@the8472 I went down multiple paths with this and the only reasonable improvement was to change any calls to state-bound methods to be explicit with an InvalidContext error instead of what would appear to be a NoMethodError. Because of the way the methods get defined and how they could be defined in superclasses (whether explicitly or via method_missing) it's not possible to change the behavior of respond_to?).

It could be possible to define something like state_respond_to? that only checks for state-bound methods, but I don't have any plans to implement that for the time being. I can consider it was part of the 2.0 release.

@obrie obrie was assigned
@shuhaowu shuhaowu referenced this issue from a commit in Shopify/state_machine
@obrie obrie Raise InvalidContext error when the current state does not define a s…
…tate-driven behavior. Closes #196
2dbb0c5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.