Skip to content
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

AASM generator #463

Merged
merged 3 commits into from
Sep 3, 2021
Merged

AASM generator #463

merged 3 commits into from
Sep 3, 2021

Commits on Sep 2, 2021

  1. AASM generator

    This commit adds a generator for the AASM state machine gem. AASM allows you to define a state machine with states, events, and transitions. Each of these generates various things in the owning class.
    
    * For each state `xxx`
      * A constant `STATE_XXX` with the value that is stored in the state column
      * A method `xxx?` that allows you to query for if the owning class is in that state
    * For each event `xxx`
      * A method `xxx` that triggers that event
      * A method `xxx!` that triggers that event and potentially raises an error
      * A method `xxx_without_validation!` that triggers that event and skips validation
      * A method `may_xxx?` that runs the validation but does not trigger that event
    
    This gem relies very heavily on `instance_eval`. For example, in the follow snippet:
    
    ```ruby
    class StateMachine
      include AASM
      extend T::Sig
    
      aasm do
        # This block is evaluated in the context of a new AASM::Base object.
        # We _could_ shim this class to get the right binding for the aasm
        # method, but see below.
    
        state :sleeping, initial: true
        state :running, :cleaning
    
        event :run do
          # This block is evaluated in the context of a new
          # AASM::Core::Event object. We could also shim this class to get
          # the right binding for the event method, but see below.
    
          before do
            # This block is evaluated all of the way back up in the
            # StateMachine class, which means that before_run here will
            # actually evaluate properly. So even if we were to shim the
            # aasm and event methods, there's no way to shim it such that
            # this method call will evaluate without either
            # T.bind(T.attached_class) which doesn't exist or forcing the
            # consumers to always T.bind(self, StateMachine) within each
            # callback.
            before_run
          end
    
          transitions from: :sleeping, to: :running
        end
      end
    
      private
    
      sig { void }
      def before_run; end
    end
    ```
    
    To get around the problems mentioned in the snippet above, we generate a private PrivateAASMMachine constant within each class that includes a state machine where we properly bind the callback methods. You can see the spec for a detailed layout of what gets generated.
    kddnewton authored and Ryan Brushett committed Sep 2, 2021
    Configuration menu
    Copy the full SHA
    f34889f View commit details
    Browse the repository at this point in the history

Commits on Sep 3, 2021

  1. Add test for include but no aasm call

    Ryan Brushett committed Sep 3, 2021
    Configuration menu
    Copy the full SHA
    e7c035e View commit details
    Browse the repository at this point in the history
  2. Increase type safety

    paracycle committed Sep 3, 2021
    Configuration menu
    Copy the full SHA
    0fba1e0 View commit details
    Browse the repository at this point in the history