-
-
Notifications
You must be signed in to change notification settings - Fork 40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NoMethodError problem #18
Comments
HI @jasonl99, thanks for using the library! If possible at all, could you please paste in the code that causes this, that would definitely help in zeroing on the issue. |
Of course! (and thank you for the library by the way)... I think the problem I'm running into is this line: self.current_state = self.fm.current.to_s Once I commented that out in my code, I no longer received the error. It's been there since the beginning about version 0.50, but I'm wondering if this is bouncing back and forth between states somehow. It does look like the error is being caused by stack level too deep type situation that isn't being caught. The code below is in a "FiniteMachine" module which is included in various models. def fm
context = self
@fm ||= FiniteMachine.define do
target(context)
initial get_state
terminal :completed
events {
event :validated, [:none, :admin_review, :invalid] => :valid
event :validated, ready: :ready # effectively, this is revalidating
event :invalidated, [:admin_review, :valid] => :invalid
event :flagged, [:valid, :ready, :final] => :admin_review
event :readied, [:valid, :ready] => :ready
event :finalized, [:ready,:valid,:admin_review ] => :final
event :scored, final: :scored
event :closed, [:admin_review, :scored ] => :complete
}
callbacks {
on_transition {|event| set_state(event)}
}
handle FiniteMachine::TransitionError, with: proc { |exception| log "Error transitioning in state machine [#{exception.message}]", :error}
end
end
def set_state(event)
puts "Attempting to set state to #{event.to} #{Time.now.to_i}"
# queueing will probably happen here, but for now, just call the stuff directly
log "Setting entity state to #{event.to} ", :info
case event.to
when :valid
log "Entity has been validated", :debug
# context.create_timeframes
when :ready
log 'Entity has been readied', :debug
when :admin_review
log "Entity has been flagged and set to notify admin", :error
# notify admin, adjust timeframes to be unavailable, etc.
when :final
log 'Entity finalized',:debug
# run context.score_results
# self.scored
else
end
# self.current_state = self.fm.current.to_s
end
def get_state
self.current_state
end
end |
I haven't looked at my finite_machine code for a good couple of months, and I'm pretty sure something is just ping-ponging the state back and forth (I'm almost certain it's related to how the states are set vs how they were set in version 0.50). I'll mark this as closed for now and I'm going to redo my states and see what happens. |
Just a quick note: I think I found part of the issue. If I call this: myobject.fm.blah |
#method_missing in the StateMachine module is the cause for me (and it was my own bug that exposed the problem). If target responds to a method, it is called regardless of whether or not it is a defined event. This was a problem in my code because I had a 'finalized' event in finite_machine, and a 'finalize' method that was used to apply the finalized state. I accidentally called fm.finalize (instead of fm.finalized) which meant that the state never changed, but the finalization code kept being called. I suggest you raise an error in #method_missing if a call is made to a method that is not a defined event. Either that, or I am completely misunderstanding how to use this gem :) |
This behaviour is intended, that is, when you call, for instance, methods inside the callback they are called on target context if they are not events themeselves. However I agree that calling a target object method outside of finite machine definition should probably raise the error. I suppose this would be harder to implement as I currently do not store the context of execution and verify that it happens in the block scope of, for example, callback definition. |
I'm not sure it needs to be complicated... In the method_messing method def method_missing(method_name, *args, &block)
if target.respond_to?(method_name.to_sym)
target.public_send(method_name.to_sym, *args, &block)
elsif observer.respond_to?(method_name.to_sym)
observer.public_send(method_name.to_sym, *args, &block)
else
super
end
end If you just changed if target.respond_to?(method_name.to_sym) to if target.respond_to?(method_name.to_sym) && self.transitions.keys.include?(method_name) I think that would be enough, right? |
I'm don't think your solution addresses the problem. Let's say you have as your target ActiveRecord instance called on_enter :green do
save
end With the proposed solution this simply wouldn't work as the car.fsm.save # => this should raise error as we don't want to execute target methods on state machine However, if you are inside the callback |
In your example, if you simply added context, would that work? on_enter :green do
context.save
end I'd be a little worried about finite machine's auto-created method names hijacking the names of the context's methods. For example, if I have a finite machine that targets an ActiveRecord object, and a finite machine event #save which one is called? The finite machine save or the context.save? What about #save! (if both had a #save! method). By requiring the target object (context.save) the namespace automatically avoids clashes. I think this discussion helps me understand the intent of the #target method. |
Agree. You should be able to do it now but instead of |
@jasonl99 I have removed the implicit context when the state machine is associated with another object through on_enter :green do |event|
target.save # => executes save on target object
save # => executes event called save or raises error 'method undefined'
end As you rightly pointed out this will simplify interaction with the FiniteMachine in the future and remove unambiguous calls. In other words, state machine will only be able to call its own methods unless told explicitly to call methods on target. This is part of new |
NoMethodError: undefined method
<=' for #<NoMethodError:0x0000003c773d50> from /home/jason/.rvm/gems/ruby-2.1.2/gems/finite_machine-0.7.1/lib/finite_machine/catchable.rb:58:in
block in handler_for_error'Just started getting these, and haven't had any time to figure out why.
The text was updated successfully, but these errors were encountered: