Skip to content

aasm 6.0 compiler emits non-existent event methods for namespaced state machines #2671

Description

@allan-thatch

The built-in Tapioca::Dsl::Compilers::AASM generates method definitions that do not exist at runtime for namespaced state machines when using aasm >= 6.0:

model.create_method(event.name.to_s, parameters: parameters)
model.create_method("#{event.name}!", parameters: parameters)
model.create_method("#{event.name}_without_validation!", parameters: parameters)
model.create_method("may_#{event.name}?", return_type: "T::Boolean")
# For events, if there's a namespace the default methods are created in addition to
# namespaced ones.
next unless namespace
name = "#{event.name}_#{namespace}"
model.create_method(name.to_s, parameters: parameters)
model.create_method("#{name}!", parameters: parameters)
model.create_method("may_#{name}?", return_type: "T::Boolean")

This causes issues with the introduction of aasm/aasm#880, since the plain methods are no longer defined. From that pull request:

This is a breaking change: plain-named event methods (sell!, may_sell?) are no longer defined when a namespace is active. Update all call sites to use the namespaced form.

Only the namespaced form exists, but the compiler still emits the plain forms unconditionally even though none exist at runtime or test time. (I discovered this during a Dependabot update that caused unit tests to fail.)

Environment

  • tapioca: 0.19.1
  • aasm: 6.0.0
  • sorbet-static: 0.6.13329

Repro

class Light
  include AASM

  aasm :power, namespace: :power do
    state :off, initial: true
    state :on

    event :turn_on do
      transitions from: :off, to: :on
    end
  end
end

Runtime behavior under aasm 6.0.0:

Light.new.respond_to?(:turn_on!)           # => false   (plain form removed in aasm 6)
Light.new.respond_to?(:turn_on_power!)     # => true    (namespaced form)
Light.new.respond_to?(:may_turn_on?)       # => false
Light.new.respond_to?(:may_turn_on_power?) # => true

Generated RBI:

class Light
  def turn_on(*opts, &block); end                     # phantom
  def turn_on!(*opts, &block); end                    # phantom
  def turn_on_without_validation!(*opts, &block); end # phantom
  def may_turn_on?; end                               # phantom

  def turn_on_power(*opts, &block); end               # real
  def turn_on_power!(*opts, &block); end              #
  def may_turn_on_power?; end                         # real
end

Notes

I'm going to try to test a patch in our internal use cases to ensure compatibility and will try to submit an upstream pull request. Also related: #2666 (has no updates to the compiler)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions