该软件包包含AASM,一个用于在Ruby类中添加有限状态机的库。
AASM始于ACTS_AS_STATE_MACHINE插件,但已演变为更通用的库,该库不再仅针对ActivereCord模型。它目前为许多ORMS提供适配器,但无论其具有哪个父类别(如果有),都可以用于任何Ruby类。
查看readme_from_version_3_to_4有关如何从ASM的3.x版切换到4.0的详细信息。
添加状态机很简单,就像包括AASM模块并开始定义状态和事件及其过渡:
class Job
include AASM
aasm do
state :sleeping , initial : true
state :running , :cleaning
event :run do
transitions from : :sleeping , to : :running
end
event :clean do
transitions from : :running , to : :cleaning
end
event :sleep do
transitions from : [ :running , :cleaning ] , to : :sleeping
end
end
end这为您提供了几种课堂Job实例的公共方法:
job = Job . new
job . sleeping? # => true
job . may_run? # => true
job . run
job . running? # => true
job . sleeping? # => false
job . may_run? # => false
job . run # => raises AASM::InvalidTransition如果您不喜欢例外,并且喜欢简单的true或false作为响应,请告诉Aasm不要发牢骚:
class Job
...
aasm whiny_transitions : false do
...
end
end
job . running? # => true
job . may_run? # => false
job . run # => false触发事件时,您可以将块传递到该方法,只有在过渡成功时才会调用它:
job . run do
job . user . notify_job_ran # Will be called if job.may_run? is true
end您可以为您的事件,过渡和状态定义许多回调。当满足某些标准时,将调用这些方法,PROCS或类,例如进入特定状态:
class Job
include AASM
aasm do
state :sleeping , initial : true , before_enter : :do_something
state :running , before_enter : Proc . new { do_something && notify_somebody }
state :finished
after_all_transitions :log_status_change
event :run , after : :notify_somebody do
before do
log ( 'Preparing to run' )
end
transitions from : :sleeping , to : :running , after : Proc . new { |* args | set_process ( * args ) }
transitions from : :running , to : :finished , after : LogRunTime
end
event :sleep do
after do
...
end
error do | e |
...
end
transitions from : :running , to : :sleeping
end
end
def log_status_change
puts "changing from #{ aasm . from_state } to #{ aasm . to_state } (event: #{ aasm . current_event } )"
end
def set_process ( name )
...
end
def do_something
...
end
def notify_somebody
...
end
end
class LogRunTime
def call
log "Job was running for X seconds"
end
end在这种情况下,在实际进入状态sleeping之前,请调用do_something ,而在过渡run (从sleeping到running )完成后,请调用notify_somebody 。
AASM还将在上面的示例中从running到finished后的过渡到完成后call LogRunTime 。您可以通过在上面定义初始化方法将参数传递给课程:这样:
请注意,Procs是在记录的上下文中执行的,这意味着您无需将记录作为参数,只需调用所需的方法即可。
class LogRunTime
# optional args parameter can be omitted, but if you define initialize
# you must accept the model instance as the first parameter to it.
def initialize ( job , args = { } )
@job = job
end
def call
log "Job was running for #{ @job . run_time } seconds"
end
end 您可以将参数传递给事件:
job = Job . new
job . run ( :defragmentation )所有警卫和回调后都会收到这些参数。在这种情况下, set_process将与以下方式调用:defragmentation参数。
如果事件的第一个参数是状态(例如:running或:finished ),则第一个参数被消耗,并且状态机将尝试过渡到该状态。为后卫和回调添加逗号分隔参数
job = Job . new
job . run ( :running , :defragmentation )在这种情况下, set_process不会被调用,作业将过渡到运行状态,而回调将接收:defragmentation为参数
如果在事件处理过程中发生错误的情况下,将救出错误并将其传递给:error回调,该错误可以处理或重新汇总以进行进一步传播。
另外,您可以定义一个方法,如果任何事件失败:
def aasm_event_failed ( event_name , old_state_name )
# use custom exception/messages, report metrics, etc
end在过渡期间:after (仅此而可靠地,或在全局after_all_transitions回调中),您可以访问原始状态(从国家 /地区)和目标状态(to to nate),例如:
def set_process ( name )
logger . info "from #{ aasm . from_state } to #{ aasm . to_state } "
end 在这里,您可以看到所有可能的回调列表,以及他们的呼叫顺序:
begin
event before_all_events
event before
event guards
transition guards
old_state before_exit
old_state exit
after_all_transitions
transition after
new_state before_enter
new_state enter
... update state ...
event before_success # if persist successful
transition success # if persist successful, database update not guaranteed
event success # if persist successful, database update not guaranteed
old_state after_exit
new_state after_enter
event after
event after_all_events
rescue
event error
event error_on_all_events
ensure
event ensure
event ensure_on_all_events
end如果应该在数据库更新后触发事件的after_commit回调。
在运行回调时,您可以轻松地检索通过使用aasm.current_event触发的事件的名称:
# taken the example callback from above
def do_something
puts "triggered #{ aasm . current_event } "
end进而
job = Job . new
# without bang
job . sleep # => triggered :sleep
# with bang
job . sleep! # => triggered :sleep!假设只有在给出定义的条件时,您才需要允许特定的过渡。为此,您可以在每个过渡之前设置一个警卫,该后期将在实际运行过渡之前运行。如果警卫队返回false则过渡将被拒绝(提高AASM::InvalidTransition ):
class Cleaner
include AASM
aasm do
state :idle , initial : true
state :cleaning
event :clean do
transitions from : :idle , to : :cleaning , guard : :cleaning_needed?
end
event :clean_if_needed do
transitions from : :idle , to : :cleaning do
guard do
cleaning_needed?
end
end
transitions from : :idle , to : :idle
end
event :clean_if_dirty do
transitions from : :idle , to : :cleaning , guard : :if_dirty?
end
end
def cleaning_needed?
false
end
def if_dirty? ( status )
status == :dirty
end
end
job = Cleaner . new
job . may_clean? # => false
job . clean # => raises AASM::InvalidTransition
job . may_clean_if_needed? # => true
job . clean_if_needed! # idle
job . clean_if_dirty ( :clean ) # => raises AASM::InvalidTransition
job . clean_if_dirty ( :dirty ) # => true您甚至可以提供许多警卫,所有这些都必须成功继续
def walked_the_dog? ; ... ; end
event :sleep do
transitions from : :running , to : :sleeping , guards : [ :cleaning_needed? , :walked_the_dog? ]
end如果您想为活动中的所有过渡提供警卫,可以使用事件警卫
event :sleep , guards : [ :walked_the_dog? ] do
transitions from : :running , to : :sleeping , guards : [ :cleaning_needed? ]
transitions from : :cleaning , to : :sleeping
end如果您喜欢更类似红宝石的警卫语法,则可以使用if unless可以使用:
event :clean do
transitions from : :running , to : :cleaning , if : :cleaning_needed?
end
event :sleep do
transitions from : :running , to : :sleeping , unless : :cleaning_needed?
end
end如果班级响应call ,您可以调用课程而不是方法
event :sleep do
transitions from : :running , to : :sleeping , guards : Dog
end class Dog
def call
cleaning_needed? && walked?
end
...
end如果事件有多个过渡,成功完成的第一个过渡将阻止在同一事件中处理其他过渡。
require 'aasm'
class Job
include AASM
aasm do
state :stage1 , initial : true
state :stage2
state :stage3
state :completed
event :stage1_completed do
transitions from : :stage1 , to : :stage3 , guard : :stage2_completed?
transitions from : :stage1 , to : :stage2
end
end
def stage2_completed?
true
end
end
job = Job . new
job . stage1_completed
job . aasm . current_state # stage3您可以通过省略from方式来定义从任何定义状态的过渡:
event :abort do
transitions to : :aborted
end您可以使用以下方式定义状态显示名称
class Job
include AASM
aasm do
state :stage1 , initial : true , display : 'First Stage'
state :stage2
state :stage3
end
end
job = Job . new
job . aasm . human_state每个课程都支持多台状态机。请注意,尽管考虑到每个班级的一台状态机,但AASM已构建。尽管如此,这是这样做的方法(见下文)。请注意,您将需要指定数据库列为您的相关状态存储的位置 - 我们在下面的示例中指定了两个列move_state和work_state 。有关更多信息,请参见“列”和“迁移”部分。
class SimpleMultipleExample
include AASM
aasm ( :move , column : 'move_state' ) do
state :standing , initial : true
state :walking
state :running
event :walk do
transitions from : :standing , to : :walking
end
event :run do
transitions from : [ :standing , :walking ] , to : :running
end
event :hold do
transitions from : [ :walking , :running ] , to : :standing
end
end
aasm ( :work , column : 'work_state' ) do
state :sleeping , initial : true
state :processing
event :start do
transitions from : :sleeping , to : :processing
end
event :stop do
transitions from : :processing , to : :sleeping
end
end
end
simple = SimpleMultipleExample . new
simple . aasm ( :move ) . current_state
# => :standing
simple . aasm ( :work ) . current_state
# => :sleeping
simple . start
simple . aasm ( :move ) . current_state
# => :standing
simple . aasm ( :work ) . current_state
# => :processing AASM不禁止在多个状态机器中定义同一事件。如果没有提供名称空间,则最新的定义“获胜”并覆盖了先前的定义。但是,发出警告: SimpleMultipleExample: overriding method 'run'! 。
另外,您可以为每个状态机提供一个名称空间:
class NamespacedMultipleExample
include AASM
aasm ( :status ) do
state :unapproved , initial : true
state :approved
event :approve do
transitions from : :unapproved , to : :approved
end
event :unapprove do
transitions from : :approved , to : :unapproved
end
end
aasm ( :review_status , namespace : :review ) do
state :unapproved , initial : true
state :approved
event :approve do
transitions from : :unapproved , to : :approved
end
event :unapprove do
transitions from : :approved , to : :unapproved
end
end
end
namespaced = NamespacedMultipleExample . new
namespaced . aasm ( :status ) . current_state
# => :unapproved
namespaced . aasm ( :review_status ) . current_state
# => :unapproved
namespaced . approve_review
namespaced . aasm ( :review_status ) . current_state
# => :approved所有AASM类和实例级aasm方法都接受状态计算机选择器。因此,例如,要在班级上使用检查,您必须使用
SimpleMultipleExample . aasm ( :move ) . states . map ( & :name )
# => [:standing, :walking, :running]允许事件绑定到另一个
class Example
include AASM
aasm ( :work ) do
state :sleeping , initial : true
state :processing
event :start do
transitions from : :sleeping , to : :processing
end
event :stop do
transitions from : :processing , to : :sleeping
end
end
aasm ( :question ) do
state :answered , initial : true
state :asked
event :ask , binding_event : :start do
transitions from : :answered , to : :asked
end
event :answer , binding_event : :stop do
transitions from : :asked , to : :answered
end
end
end
example = Example . new
example . aasm ( :work ) . current_state #=> :sleeping
example . aasm ( :question ) . current_state #=> :answered
example . ask
example . aasm ( :work ) . current_state #=> :processing
example . aasm ( :question ) . current_state #=> :askedAASM自动为每个状态生成常数,因此您不必明确定义它们。
class Foo
include AASM
aasm do
state :initialized
state :calculated
state :finalized
end
end
> Foo :: STATE_INITIALIZED
#=> :initialized
> Foo :: STATE_CALCULATED
#=> :calculated AASM可让您轻松地扩展AASM::Base出于自己的应用目的。
假设我们在许多AASM模型中都有共同的逻辑。我们可以在AASM::Base的子类中体现这种逻辑。
class CustomAASMBase < AASM :: Base
# A custom transition that we want available across many AASM models.
def count_transitions!
klass . class_eval do
aasm with_klass : CustomAASMBase do
after_all_transitions :increment_transition_count
end
end
end
# A custom annotation that we want available across many AASM models.
def requires_guards!
klass . class_eval do
attr_reader :authorizable_called ,
:transition_count ,
:fillable_called
def authorizable?
@authorizable_called = true
end
def fillable?
@fillable_called = true
end
def increment_transition_count
@transition_count ||= 0
@transition_count += 1
end
end
end
end当我们声明具有AASM状态计算机的模型时,我们只需将aasm块带有a :with_klass键的aasm块。
class SimpleCustomExample
include AASM
# Let's build an AASM state machine with our custom class.
aasm with_klass : CustomAASMBase do
requires_guards!
count_transitions!
state :initialised , initial : true
state :filled_out
state :authorised
event :fill_out do
transitions from : :initialised , to : :filled_out , guard : :fillable?
end
event :authorise do
transitions from : :filled_out , to : :authorised , guard : :authorizable?
end
end
endAASM具有对ActivereCord的支持,并允许在数据库中自动持续对象状态。
将gem 'after_commit_everywhere', '~> 1.0'添加到您的gemfile。
class Job < ActiveRecord :: Base
include AASM
aasm do # default column: aasm_state
state :sleeping , initial : true
state :running
event :run do
transitions from : :sleeping , to : :running
end
event :sleep do
transitions from : :running , to : :sleeping
end
end
end您可以告诉AASM自动保存对象或将其保存下来
job = Job . new
job . run # not saved
job . run! # saved
# or
job . aasm . fire ( :run ) # not saved
job . aasm . fire! ( :run ) # saved保存包括在Job类上运行所有验证。如果将whiny_persistence标志设置为true ,则在失败的情况下会增加异常。如果将whiny_persistence标志设置为false ,则爆炸的方法返回true如果状态过渡成功或false (如果发生错误)。
如果要确保在没有运行验证的情况下保存状态(从而可以持续无效对象状态),只需告诉AASM跳过验证。请注意,在跳过验证时,只有状态列将在数据库中进行更新(就像ActivereCord update_column正在工作一样)。
class Job < ActiveRecord :: Base
include AASM
aasm skip_validation_on_save : true do
state :sleeping , initial : true
state :running
event :run do
transitions from : :sleeping , to : :running
end
event :sleep do
transitions from : :running , to : :sleeping
end
end
end另外,您可以使用some_event_name_without_validation!方法。因此,您可以灵活地默认情况下对所有过渡进行验证,然后在需要时跳过它。请注意,只有如上示例中提到的状态列会更新。
job . run_without_validation!如果要确保未直接分配用于存储状态的AASM列,请配置AASM以不允许直接分配,例如:
class Job < ActiveRecord :: Base
include AASM
aasm no_direct_assignment : true do
state :sleeping , initial : true
state :running
event :run do
transitions from : :sleeping , to : :running
end
end
end因此:
job = Job . create
job . aasm_state # => 'sleeping'
job . aasm_state = :running # => raises AASM::NoDirectAssignmentError
job . aasm_state # => 'sleeping'您可以告诉AASM在输入新状态时尝试编写时间戳。如果设置了timestamps: true , AASM将寻找一个名为“新状态加_at的字段,并尝试填充它:
class Job < ActiveRecord :: Base
include AASM
aasm timestamps : true do
state :sleeping , initial : true
state :running
event :run do
transitions from : :sleeping , to : :running
end
end
end因此:
job = Job . create
job . running_at # => nil
job . run!
job . running_at # => 2020-02-20 20:00:00缺少时间戳字段被默默地忽略,因此使用此选项时,没有必要为所有状态使用设置器(例如ActivereCord列)。
您可以在您的状态列中使用Rails 4.1+中的枚举:
class Job < ActiveRecord :: Base
include AASM
enum state : {
sleeping : 5 ,
running : 99
}
aasm column : :state , enum : true do
state :sleeping , initial : true
state :running
end
end您可以明确传递该方法的名称,该方法可作为枚举映射访问作为enum的值,也可以简单地将其设置为true 。在后一种情况下,AASM将尝试使用多个列名称访问可能的枚举状态。
此外,如果您的列具有整数类型(通常是在使用Rails Enums工作时的情况),则可以省略:enum设置 - Aasm自动检测到这种情况并启用了枚举支持。如果出现任何问题,您可以通过设置:enum到false禁用枚举功能,并通过设置为默认行为。
除了Activerecord和Mongoid ,Aasm还支持续集。
class Job < Sequel :: Model
include AASM
aasm do # default column: aasm_state
...
end
end但是,它的功能尚未像activerecord那样完整。例如,尚未定义范围。请参阅自动示波器。
由于版本4.8.0 ASM还支持Dongrogoid作为持久性ORM。
如果您使用的是mongoid,AASM还支持对MongoDB的持久性。在包含aasm之前,请确保在包含aasm之前包含mongoid ::文档。
class Job
include Mongoid :: Document
include AASM
field :aasm_state
aasm do
...
end
end如果您使用的是Nobrainer,AASM还支持持续重新InkinkDB。在包含aasm之前,请确保在包含aasm之前包含nobrainer ::文档。
class Job
include NoBrainer :: Document
include AASM
field :aasm_state
aasm do
...
end
endAASM还通过redis ::对象支持Redis的持久性。在包含aasm之前,请确保包括redis ::对象。请注意,非爆炸事件将作为爆炸事件起作用,坚持每个呼叫的更改。
class User
include Redis :: Objects
include AASM
aasm do
end
endAASM将自动为模型中的每个状态创建范围方法。
class Job < ActiveRecord :: Base
include AASM
aasm do
state :sleeping , initial : true
state :running
state :cleaning
end
def self . sleeping
"This method name is already in use"
end
end class JobsController < ApplicationController
def index
@running_jobs = Job . running
@recent_cleaning_jobs = Job . cleaning . where ( 'created_at >= ?' , 3 . days . ago )
# @sleeping_jobs = Job.sleeping #=> "This method name is already in use"
end
end如果您不需要范围(或根本不想要它们),请在定义AASM状态时禁用它们的创建,例如:
class Job < ActiveRecord :: Base
include AASM
aasm create_scopes : false do
state :sleeping , initial : true
state :running
state :cleaning
end
end由于版本3.0.13 ASM支持ActivereCord交易。因此,每当过渡回调或状态更新失败时,所有数据库记录的所有更改都会回滚。 MongoDB不支持交易。
目前可以在活动中处理3个交易回调,以及所有活动的2个交易回调。
event before_all_transactions
event before_transaction
event aasm_fire_event ( within transaction )
event after_commit ( if event successful )
event after_transaction
event after_all_transactions如果要确保仅在进行交易后才发生依赖诉讼,请使用after_commit回调以及自动保存(BANG)方法,例如:
class Job < ActiveRecord :: Base
include AASM
aasm do
state :sleeping , initial : true
state :running
event :run , after_commit : :notify_about_running_job do
transitions from : :sleeping , to : :running
end
end
def notify_about_running_job
...
end
end
job = Job . where ( state : 'sleeping' ) . first!
job . run! # Saves the model and triggers the after_commit callback请注意,以下内容不会运行after_commit回调,因为未使用自动保存方法:
job = Job . where ( state : 'sleeping' ) . first!
job . run
job . save! #notify_about_running_job is not run请注意:after_commit aasm回调围绕交易模式的自定义实现而不是真实的数据库事务。这一事实仍然导致种族条件和嵌套交易中的冗余回调调用。为了解决该问题,强烈建议将gem 'after_commit_everywhere', '~> 1.0'添加到您的Gemfile中,〜> 1.0'。
如果要将状态变化封装在自己的交易中,则此嵌套交易的行为可能会造成混淆。如果您想进一步了解此事,请看一下ActivereCord嵌套交易。然而,默认情况下,AASM需要一项新的事务transaction(requires_new: true) 。您可以通过更改配置来覆盖此行为
class Job < ActiveRecord :: Base
include AASM
aasm requires_new_transaction : false do
...
end
...
end然后导致transaction(requires_new: false) ,导轨默认值。
此外,如果您不希望将任何ActiverEcord操作包裹在交易中,则可以指定use_transactions标志。如果您想将事物持续到由于事务或回调而发生的数据库,即使发生某些错误,这可能会很有用。默认情况下, use_transactions标志是正确的。
class Job < ActiveRecord :: Base
include AASM
aasm use_transactions : false do
...
end
...
endAASM支持Activerecord的悲观锁定, with_lock用于数据库持久性层。
| 选项 | 目的 |
|---|---|
false (默认) | 没有锁 |
true | 获得阻止悲观锁,例如FOR UPDATE |
| 细绳 | 根据SQL字符串获得锁,例如FOR UPDATE NOWAIT |
class Job < ActiveRecord :: Base
include AASM
aasm requires_lock : true do
...
end
...
end class Job < ActiveRecord :: Base
include AASM
aasm requires_lock : 'FOR UPDATE NOWAIT' do
...
end
...
end作为默认,AASM使用列aasm_state存储状态。您可以通过定义您喜欢的列名,使用以下列来覆盖此:column :
class Job < ActiveRecord :: Base
include AASM
aasm column : :my_state do
...
end
aasm :another_state_machine , column : :second_state do
...
end
end无论使用哪种列名称,请确保添加迁移以提供此列(类型string )。请勿在数据库级别添加列的默认值。如果您在数据库中添加默认值,则在模型实例化后将不会触发初始状态的AASM回调。
class AddJobState < ActiveRecord :: Migration
def self . up
add_column :jobs , :aasm_state , :string
end
def self . down
remove_column :jobs , :aasm_state
end
end可以使用Paper_trail Gem进行记录状态更改
可以在此处找到实施的示例
AASM支持有关状态和事件的查询方法
给定以下Job类:
class Job
include AASM
aasm do
state :sleeping , initial : true
state :running , :cleaning
event :run do
transitions from : :sleeping , to : :running
end
event :clean do
transitions from : :running , to : :cleaning , guard : :cleaning_needed?
end
event :sleep do
transitions from : [ :running , :cleaning ] , to : :sleeping
end
end
def cleaning_needed?
false
end
end # show all states
Job . aasm . states . map ( & :name )
#=> [:sleeping, :running, :cleaning]
job = Job . new
# show all permitted states (from initial state)
job . aasm . states ( permitted : true ) . map ( & :name )
#=> [:running]
# List all the permitted transitions(event and state pairs) from initial state
job . aasm . permitted_transitions
#=> [{ :event => :run, :state => :running }]
job . run
job . aasm . states ( permitted : true ) . map ( & :name )
#=> [:sleeping]
# show all non permitted states
job . aasm . states ( permitted : false ) . map ( & :name )
#=> [:cleaning]
# show all possible (triggerable) events from the current state
job . aasm . events . map ( & :name )
#=> [:clean, :sleep]
# show all permitted events
job . aasm . events ( permitted : true ) . map ( & :name )
#=> [:sleep]
# show all non permitted events
job . aasm . events ( permitted : false ) . map ( & :name )
#=> [:clean]
# show all possible events except a specific one
job . aasm . events ( reject : :sleep ) . map ( & :name )
#=> [:clean]
# list states for select
Job . aasm . states_for_select
#=> [["Sleeping", "sleeping"], ["Running", "running"], ["Cleaning", "cleaning"]]
# show permitted states with guard parameter
job . aasm . states ( { permitted : true } , guard_parameter ) . map ( & :name )默认情况下,警告将打印到STDERR 。如果要将这些警告记录到另一个输出,请使用
class Job
include AASM
aasm logger : Rails . logger do
...
end
end您可以通过设置AASM::Configuration.hide_warnings = true隐藏警告
现在支持Codedataquery!但是,我仍在向其存储库提交兼容性更新。同时,您可以使用我的叉子,可能仍然存在一些小问题,但我打算自己广泛使用它,因此修复程序应该很快。
警告:
AASM为RSPEC提供了一些匹配器:
transition_from ,have_state , allow_eventallow_transition_to 。 require 'aasm/rspec'到您的spec_helper.rb文件。 # classes with only the default state machine
job = Job . new
expect ( job ) . to transition_from ( :sleeping ) . to ( :running ) . on_event ( :run )
expect ( job ) . not_to transition_from ( :sleeping ) . to ( :cleaning ) . on_event ( :run )
expect ( job ) . to have_state ( :sleeping )
expect ( job ) . not_to have_state ( :running )
expect ( job ) . to allow_event :run
expect ( job ) . to_not allow_event :clean
expect ( job ) . to allow_transition_to ( :running )
expect ( job ) . to_not allow_transition_to ( :cleaning )
# on_event also accept multiple arguments
expect ( job ) . to transition_from ( :sleeping ) . to ( :running ) . on_event ( :run , :defragmentation )
# classes with multiple state machine
multiple = SimpleMultipleExample . new
expect ( multiple ) . to transition_from ( :standing ) . to ( :walking ) . on_event ( :walk ) . on ( :move )
expect ( multiple ) . to_not transition_from ( :standing ) . to ( :running ) . on_event ( :walk ) . on ( :move )
expect ( multiple ) . to have_state ( :standing ) . on ( :move )
expect ( multiple ) . not_to have_state ( :walking ) . on ( :move )
expect ( multiple ) . to allow_event ( :walk ) . on ( :move )
expect ( multiple ) . to_not allow_event ( :hold ) . on ( :move )
expect ( multiple ) . to allow_transition_to ( :walking ) . on ( :move )
expect ( multiple ) . to_not allow_transition_to ( :running ) . on ( :move )
expect ( multiple ) . to transition_from ( :sleeping ) . to ( :processing ) . on_event ( :start ) . on ( :work )
expect ( multiple ) . to_not transition_from ( :sleeping ) . to ( :sleeping ) . on_event ( :start ) . on ( :work )
expect ( multiple ) . to have_state ( :sleeping ) . on ( :work )
expect ( multiple ) . not_to have_state ( :processing ) . on ( :work )
expect ( multiple ) . to allow_event ( :start ) . on ( :move )
expect ( multiple ) . to_not allow_event ( :stop ) . on ( :move )
expect ( multiple ) . to allow_transition_to ( :processing ) . on ( :move )
expect ( multiple ) . to_not allow_transition_to ( :sleeping ) . on ( :move )
# allow_event also accepts arguments
expect ( job ) . to allow_event ( :run ) . with ( :defragmentation ) AASM提供了对最大的断言和类似RSPEC的期望。
支持断言的列表: assert_have_state , refute_have_state , assert_transitions_from , refute_transitions_from , assert_event_allowed , refute_event_allowed ,assert_transition_lowled, assert_transition_to_allowed , refute_transition_to_allowed 。
在您的test_helper.rb文件中添加require 'aasm/minitest' ,然后以这样的方式使用它们:
# classes with only the default state machine
job = Job . new
assert_transitions_from job , :sleeping , to : :running , on_event : :run
refute_transitions_from job , :sleeping , to : :cleaning , on_event : :run
assert_have_state job , :sleeping
refute_have_state job , :running
assert_event_allowed job , :run
refute_event_allowed job , :clean
assert_transition_to_allowed job , :running
refute_transition_to_allowed job , :cleaning
# on_event also accept arguments
assert_transitions_from job , :sleeping , :defragmentation , to : :running , on_event : :run
# classes with multiple state machine
multiple = SimpleMultipleExample . new
assert_transitions_from multiple , :standing , to : :walking , on_event : :walk , on : :move
refute_transitions_from multiple , :standing , to : :running , on_event : :walk , on : :move
assert_have_state multiple , :standing , on : :move
refute_have_state multiple , :walking , on : :move
assert_event_allowed multiple , :walk , on : :move
refute_event_allowed multiple , :hold , on : :move
assert_transition_to_allowed multiple , :walking , on : :move
refute_transition_to_allowed multiple , :running , on : :move
assert_transitions_from multiple , :sleeping , to : :processing , on_event : :start , on : :work
refute_transitions_from multiple , :sleeping , to : :sleeping , on_event : :start , on : :work
assert_have_state multiple , :sleeping , on : :work
refute_have_state multiple , :processing , on : :work
assert_event_allowed multiple , :start , on : :move
refute_event_allowed multiple , :stop , on : :move
assert_transition_to_allowed multiple , :processing , on : :move
refute_transition_to_allowed multiple , :sleeping , on : :move 支持的期望列表: must_transition_from , wont_transition_from , must_have_state , wont_have_state , must_allow_event , wont_allow_event , wont_allow_transition_to must_allow_transition_to
在您的test_helper.rb文件中添加require 'aasm/minitest_spec' ,然后以这样的方式使用它们:
# classes with only the default state machine
job = Job . new
job . must_transition_from :sleeping , to : :running , on_event : :run
job . wont_transition_from :sleeping , to : :cleaning , on_event : :run
job . must_have_state :sleeping
job . wont_have_state :running
job . must_allow_event :run
job . wont_allow_event :clean
job . must_allow_transition_to :running
job . wont_allow_transition_to :cleaning
# on_event also accept arguments
job . must_transition_from :sleeping , :defragmentation , to : :running , on_event : :run
# classes with multiple state machine
multiple = SimpleMultipleExample . new
multiple . must_transition_from :standing , to : :walking , on_event : :walk , on : :move
multiple . wont_transition_from :standing , to : :running , on_event : :walk , on : :move
multiple . must_have_state :standing , on : :move
multiple . wont_have_state :walking , on : :move
multiple . must_allow_event :walk , on : :move
multiple . wont_allow_event :hold , on : :move
multiple . must_allow_transition_to :walking , on : :move
multiple . wont_allow_transition_to :running , on : :move
multiple . must_transition_from :sleeping , to : :processing , on_event : :start , on : :work
multiple . wont_transition_from :sleeping , to : :sleeping , on_event : :start , on : :work
multiple . must_have_state :sleeping , on : :work
multiple . wont_have_state :processing , on : :work
multiple . must_allow_event :start , on : :move
multiple . wont_allow_event :stop , on : :move
multiple . must_allow_transition_to :processing , on : :move
multiple . wont_allow_transition_to :sleeping , on : :move % gem install aasm # Gemfile
gem 'aasm'% rake build
% sudo gem install pkg/aasm-x.y.z.gem安装AASM后,您可以运行生成器:
% rails generate aasm NAME [COLUMN_NAME]用模型名称替换名称,column_name是可选的(默认为'aasm_state')。这将创建一个模型(如果不存在的话)并使用AASM块进行配置。对于ActiverEcord Orm,添加了迁移文件以将AASM状态列添加到表。
轻松在Docker上运行测试套件
1. docker-compose build aasm
2. docker-compose run --rm aasm
查看ChangElog,以获取有关当前版本最近更改的详细信息。
随意
aasm的标签)该软件是“原样”提供的,并且没有任何明示或暗示的保证,包括但不限于对特定目的的商人和适合性的隐含保证。
版权(C)2006-2017 Scott Barron
特此免费授予获得此软件副本和相关文档文件副本(“软件”)的任何人,以无限制处理该软件,包括无限制的使用权,复制,复制,修改,合并,合并,发布,分发,分发,分发,订婚,和/或允许软件的副本,并允许对以下条件提供以下条件,以下是以下条件。
上述版权通知和此许可通知应包含在软件的所有副本或大量部分中。
该软件是“原样”提供的,没有任何形式的明示或暗示保证,包括但不限于适销性,特定目的的适用性和非侵权的保证。在任何情况下,作者或版权持有人都不应对任何索赔,损害赔偿或其他责任责任,无论是在合同,侵权的诉讼中还是其他责任,是由软件,使用或与软件中的使用或其他交易有关的。