Full Code of rubyist/aasm for AI

master a4bc27cff0d7 cached
70 files
106.7 KB
30.3k tokens
258 symbols
1 requests
Download .txt
Repository: rubyist/aasm
Branch: master
Commit: a4bc27cff0d7
Files: 70
Total size: 106.7 KB

Directory structure:
gitextract_cxl63xfk/

├── .document
├── .gitignore
├── .travis.yml
├── API
├── CHANGELOG.md
├── Gemfile
├── HOWTO
├── LICENSE
├── README.md
├── Rakefile
├── aasm.gemspec
├── lib/
│   ├── aasm/
│   │   ├── aasm.rb
│   │   ├── base.rb
│   │   ├── deprecated/
│   │   │   └── aasm.rb
│   │   ├── errors.rb
│   │   ├── event.rb
│   │   ├── instance_base.rb
│   │   ├── localizer.rb
│   │   ├── persistence/
│   │   │   ├── active_record_persistence.rb
│   │   │   ├── base.rb
│   │   │   └── mongoid_persistence.rb
│   │   ├── persistence.rb
│   │   ├── state.rb
│   │   ├── state_machine.rb
│   │   ├── transition.rb
│   │   └── version.rb
│   └── aasm.rb
└── spec/
    ├── database.yml
    ├── en.yml
    ├── en_deprecated_style.yml
    ├── models/
    │   ├── active_record/
    │   │   └── api.rb
    │   ├── argument.rb
    │   ├── auth_machine.rb
    │   ├── bar.rb
    │   ├── callback_new_dsl.rb
    │   ├── callback_old_dsl.rb
    │   ├── conversation.rb
    │   ├── father.rb
    │   ├── foo.rb
    │   ├── invalid_persistor.rb
    │   ├── mongoid/
    │   │   ├── simple_mongoid.rb
    │   │   └── simple_new_dsl_mongoid.rb
    │   ├── not_auto_loaded/
    │   │   └── process.rb
    │   ├── parametrised_event.rb
    │   ├── persistence.rb
    │   ├── process_with_new_dsl.rb
    │   ├── silencer.rb
    │   ├── son.rb
    │   ├── sub_classing.rb
    │   ├── this_name_better_not_be_in_use.rb
    │   ├── transactor.rb
    │   ├── validator.rb
    │   └── worker.rb
    ├── schema.rb
    ├── spec_helper.rb
    └── unit/
        ├── api_spec.rb
        ├── callbacks_spec.rb
        ├── complex_example_spec.rb
        ├── event_spec.rb
        ├── initial_state_spec.rb
        ├── inspection_spec.rb
        ├── localizer_spec.rb
        ├── memory_leak_spec.rb
        ├── new_dsl_spec.rb
        ├── persistence/
        │   ├── active_record_persistence_spec.rb
        │   └── mongoid_persistance_spec.rb
        ├── simple_example_spec.rb
        ├── state_spec.rb
        ├── subclassing_spec.rb
        └── transition_spec.rb

================================================
FILE CONTENTS
================================================

================================================
FILE: .document
================================================
README.rdoc
lib/**/*.rb
bin/*
features/**/*.feature
-
LICENSE


================================================
FILE: .gitignore
================================================
*.sw?
*~
.DS_Store
.idea
coverage
pkg
rdoc
Gemfile.lock
spec/debug.log
spec/*.db
TODO
.rvmrc
alto


================================================
FILE: .travis.yml
================================================
language: ruby
rvm:
  - 1.8.7
  - 1.9.2
  - 1.9.3
  - 2.0.0
  # - jruby-18mode # JRuby in 1.8 mode
  # - jruby-19mode # JRuby in 1.9 mode
  - rbx-18mode
  - rbx-19mode
services: mongodb


================================================
FILE: API
================================================

Overwrite method to read the current state. Used to provide another storage mechanism,
different from the standard Rails read_attribute method.

  class MyClass
    include AASM

    def aasm_read_state
      # retrieve the current state manually
    end
  end


Overwrite method to write the current state (and actually persist it). Used to provide
another storage mechanism, different from the standard Rails write_attribute method.

  class MyClass
    include AASM

    def aasm_write_state
      # store and persist the current state manually
    end
  end


Overwrite method to write the current state (without persisting it).

  class MyClass
    include AASM

    def aasm_write_state_without_persistence
      # store the current state manually
    end
  end


================================================
FILE: CHANGELOG.md
================================================
# CHANGELOG

## 3.0.19

 * fixed deprecation warning with *Rails 4* (`Relation#update_all` with conditions is deprecated)
 * fixing [issue #69](https://github.com/aasm/aasm/issues/69) ( *ActiveRecord* scopes are not chainable)

## 3.0.18

 * fixing [issue #66](https://github.com/aasm/aasm/issues/66) (state methods not reflecting the current state)

## 3.0.17

 * supporting instance level inspection for states (including permissible state, see [issue #54](https://github.com/aasm/aasm/issues/54))
 * added autocreation of constants for each state ([@jherdman](https://github.com/jherdman))

## 3.0.16

 * added autocreation of state scopes for Mongoid (thanks to [@jonnyshields](https://github.com/johnnyshields))

## 3.0.15

 * added support for localized state names (on a class level, like `Record.aasm.states.map(&:localized_name)`)

## 3.0.14

 * supporting event inspection for to-states transitions (`Event#transitions_to_state?`)

## 3.0.13

 * supporting *ActiveRecord* transactions when firing an event

## 3.0.12

 * `aasm_from_states_for_state` now supports to filter for specific transition

## 3.0.11

 * added class method `aasm_from_states_for_state` to retrieve all from states (regarding transitions) for a given state

## 3.0.10

 * added support for transitions from all other states (thanks to [@swrobel](https://github.com/swrobel))

## 3.0.9

 * guard checks (e.g. `may_edit?`) now support guard parameters as well

## 3.0.8

 * fixed issue with generating docs using yard

## 3.0.7

 * removed deprecation warning when localizing aasm state names (look at [issue #38](https://github.com/rubyist/aasm/issues/38) for details)

## 3.0.6

 * bugfix: if configured to skip validation the code does not validate anymore

## 3.0.5

 * bugfix: get rid of error with old rubygems versions

## 3.0.4

 * bugfix: Subclasses of aasm-enabled classes don't lose settings anymore (thanks to codez)

## 3.0.3

 * bugfix: ActiveRecord scopes are generated when using the new DSL

## 3.0.2

 * ActiveRecord persistence can ignore validation when trying to save invalid models

## 3.0.1

 * added support for Mongoid (Thanks, Michał Taberski)

## 3.0.0

 * switched documentation to the new DSL
 * whiny transactions: by default, raise an exception if an event transition is not possible
 * you may disable whiny transactions

## 2.4.0

 * supporting new DSL (which is much shorter)

## 2.3.1

 * bugfix: avoid naming conflict with i18n

## 2.3.0

 * supporting i18n
 * supporting regular expressions for hash values and strings



================================================
FILE: Gemfile
================================================
source 'https://rubygems.org'

gemspec


================================================
FILE: HOWTO
================================================
How to

1. Run tests for Mongoid

Start MongoDB

  $> mongod

Run the specs

  $> rspec spec/unit/persistence/mongoid_persistance_spec.rb



================================================
FILE: LICENSE
================================================
Copyright (c) 2006-2012 Scott Barron

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: README.md
================================================
# AASM - Ruby state machines [![Build Status](https://secure.travis-ci.org/aasm/aasm.png)](http://travis-ci.org/aasm/aasm) [![Code Climate](https://codeclimate.com/github/aasm/aasm.png)](https://codeclimate.com/github/aasm/aasm) [![Coverage Status](https://coveralls.io/repos/aasm/aasm/badge.png?branch=master)](https://coveralls.io/r/aasm/aasm)

This package contains AASM, a library for adding finite state machines to Ruby classes.

AASM started as the *acts_as_state_machine* plugin but has evolved into a more generic library
that no longer targets only ActiveRecord models. It currently provides adapters for
[ActiveRecord](http://api.rubyonrails.org/classes/ActiveRecord/Base.html) and
[Mongoid](http://mongoid.org/), but it can be used for any Ruby class, no matter what
parent class it has (if any).

## Usage

Adding a state machine is as simple as including the AASM module and start defining
**states** and **events** together with their **transitions**:

```ruby
class Job
  include AASM

  aasm do
    state :sleeping, :initial => true
    state :running
    state :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
```

This provides you with a couple of public methods for instances of the class `Job`:

```ruby
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
```

If you don't like exceptions and prefer a simple `true` or `false` as response, tell
AASM not to be *whiny*:

```ruby
class Job
  ...
  aasm :whiny_transitions => false do
    ...
  end
end

job.running?  # => true
job.may_run?  # => false
job.run       # => false
```

### Callbacks

You can define a number of callbacks for your transitions. These methods will be
called, when certain criteria are met, like entering a particular state:

```ruby
class Job
  include AASM

  aasm do
    state :sleeping, :initial => true, :before_enter => :do_something
    state :running

    event :run, :after => Proc.new { |user| notify_somebody(user) } do
      transitions :from => :sleeping, :to => :running, :on_transition => Proc.new {|obj, *args| obj.set_process(*args) }
    end

    event :sleep do
      after do
        ...
      end
      error do |e|
        ...
      end
      transitions :from => :running, :to => :sleeping
    end
  end

  def set_process(name)
    ...
  end

  def do_something
    ...
  end

  def notify_somebody(user)
    ...
  end

end
```

In this case `do_something` is called before actually entering the state `sleeping`,
while `notify_somebody` is called after the transition `run` (from `sleeping` to `running`)
is finished.

Here you can see a list of all possible callbacks, together with their order of calling:

```ruby
  event:before
    previous_state:before_exit
      new_state:before_enter
        ...update state...
      previous_state:after_exit
    new_state:after_enter
  event:after
```

Also, you can pass parameters to events:

```ruby
  job = Job.new
  job.run(:running, :defragmentation)
```

In this case the `set_process` would be called with `:defagmentation` argument.

In case of an error during the event processing the error is rescued and passed to `:error`
callback, which can handle it or re-raise it for further propagation.

### Guards

Let's assume you want to allow particular transitions only if a defined condition is
given. For this you can set up a guard per transition, which will run before actually
running the transition. If the guard returns `false` the transition will be
denied (raising `AASM::InvalidTransition` or returning `false` itself):

```ruby
class Job
  include AASM

  aasm do
    state :sleeping, :initial => true
    state :running
    state :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, :to => :sleeping, :guard => :cleaning_needed?
    end
  end

  def cleaning_needed?
    false
  end

end

job = Job.new
job.run
job.may_sleep?  # => false
job.sleep       # => raises AASM::InvalidTransition
```


### ActiveRecord

AASM comes with support for ActiveRecord and allows automatical persisting of the object's
state in the database.

```ruby
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
```

You can tell AASM to auto-save the object or leave it unsaved

```ruby
job = Job.new
job.run   # not saved
job.run!  # saved
```

Saving includes running all validations on the `Job` class. If you want make sure
the state gets saved without running validations (and thereby maybe persisting an
invalid object state), simply tell AASM to skip the validations:

```ruby
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
```

### Automatic Scopes

AASM will automatically create scope methods for each state in the model.

```ruby
class Job < ActiveRecord::Base
  include AASM

  aasm do
    state :sleeping, :initial => true
    state :running
    state :cleaning
  end

  def sleeping
    "This method name is in already use"
  end
end
```

```ruby
class JobsController < ApplicationController
  def index
    @running_jobs = jobs.running
    @recent_cleaning_jobs = jobs.cleaning.where('created_at >=  ?', 3.days.ago)

    # @sleeping_jobs = jobs.sleeping   #=> "This method name is in already use"
  end
end
```

### Transaction support

Since version *3.0.13* AASM supports ActiveRecord transactions. So whenever a transition
callback or the state update fails, all changes to any database record are rolled back.

### Column name & migration

As a default AASM uses the column `aasm_state` to store the states. You can override
this by defining your favorite column name, using `:column` like this:

```ruby
class Job < ActiveRecord::Base
  include AASM

  aasm :column => 'my_state' do
    ...
  end

end
```

Whatever column name is used, make sure to add a migration to provide this column
(of type `string`):

```ruby
class AddJobState < ActiveRecord::Migration
  def self.up
    add_column :jobs, :aasm_state, :string
  end

  def self.down
    remove_column :jobs, :aasm_state
  end
end
```

### <a id="inspection">Inspection

AASM supports a couple of methods to find out which states or events are provided or permissible.

Given the `Job` class from above:

```ruby
job = Job.new

job.aasm.states
=> [:sleeping, :running, :cleaning]

job.aasm.states(:permissible => true)
=> [:running]
job.run
job.aasm.states(:permissible => true)
=> [:cleaning, :sleeping]

job.aasm.events
=> [:run, :clean, :sleep]
```



## <a id="installation">Installation ##

### Manually from RubyGems.org ###

```sh
% gem install aasm
```

### Or if you are using Bundler ###

```ruby
# Gemfile
gem 'aasm'
```

### Building your own gems ###

```sh
% rake build
% sudo gem install pkg/aasm-x.y.z.gem
```

## Latest changes ##

Look at the [CHANGELOG](https://github.com/aasm/aasm/blob/master/CHANGELOG.md) for details.

## Questions? ##

Feel free to

* [create an issue on GitHub](https://github.com/aasm/aasm/issues)
* [ask a question on StackOverflow](http://stackoverflow.com) (tag with `aasm`)
* send us a tweet [@aasm](http://twitter.com/aasm)

## Authors ##

* [Scott Barron](https://github.com/rubyist)
* [Travis Tilley](https://github.com/ttilley)
* [Thorsten Böttger](http://github.com/alto)


## Warranty ##

This software is provided "as is" and without any express or
implied warranties, including, without limitation, the implied
warranties of merchantibility and fitness for a particular
purpose.

## License ##

Copyright (c) 2006-2012 Scott Barron

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: Rakefile
================================================
require 'bundler/gem_tasks'

require 'rspec/core'
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec) do |spec|
  spec.pattern = FileList['spec/**/*_spec.rb']
end

require 'rake/testtask'
Rake::TestTask.new(:test) do |test|
  test.libs << 'lib' << 'test'
  test.pattern = 'test/**/*_test.rb'
  test.verbose = true
end

require 'rdoc/task'
require 'aasm/version'

Rake::RDocTask.new do |rdoc|
  rdoc.rdoc_dir = 'rdoc'
  rdoc.title = "aasm #{AASM::VERSION}"
  rdoc.rdoc_files.include('README*')
  rdoc.rdoc_files.include('lib/**/*.rb')
end

task :default => :spec


================================================
FILE: aasm.gemspec
================================================
# -*- encoding: utf-8 -*-
$:.push File.expand_path("../lib", __FILE__)
require "aasm/version"

Gem::Specification.new do |s|
  s.name        = "aasm"
  s.version     = AASM::VERSION
  s.authors     = ["Scott Barron", "Scott Petersen", "Travis Tilley", "Thorsten Boettger"]
  s.email       = %q{scott@elitists.net, ttilley@gmail.com, aasm@mt7.de}
  s.homepage    = %q{https://github.com/aasm/aasm}
  s.summary     = %q{State machine mixin for Ruby objects}
  s.description = %q{AASM is a continuation of the acts as state machine rails plugin, built for plain Ruby objects.}
  s.date        = Time.now
  s.licenses    = ["MIT"]

  s.add_development_dependency 'activerecord', '3.2.12'
  # s.add_development_dependency 'activerecord', '4.0.0.rc1'

  s.add_development_dependency 'mongoid' if Gem::Version.create(RUBY_VERSION.dup) >= Gem::Version.create('1.9.3')
  s.add_development_dependency 'rake'
  s.add_development_dependency 'sdoc'
  s.add_development_dependency 'rspec', '~> 2.0'
  s.add_development_dependency 'rr'
  s.add_development_dependency 'sqlite3'
  s.add_development_dependency 'minitest'
  # s.add_development_dependency 'debugger'
  # s.add_development_dependency 'pry'
  s.add_development_dependency 'ruby-debug-completion'
  s.add_development_dependency 'coveralls'

  s.files         = `git ls-files`.split("\n")
  s.test_files    = `git ls-files -- {test,spec,features}/*`.split("\n")
  s.executables   = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
  s.require_paths = ["lib"]
end


================================================
FILE: lib/aasm/aasm.rb
================================================
module AASM

  def self.included(base) #:nodoc:
    base.extend AASM::ClassMethods

    # do not overwrite existing state machines, which could have been created by
    # inheritance, see class method inherited
    AASM::StateMachine[base] ||= AASM::StateMachine.new('')

    AASM::Persistence.load_persistence(base)
    super
  end

  module ClassMethods

    # make sure inheritance (aka subclassing) works with AASM
    def inherited(base)
      AASM::StateMachine[base] = AASM::StateMachine[self].clone
      super
    end

    # this is the entry point for all state and event definitions
    def aasm(options={}, &block)
      @aasm ||= AASM::Base.new(self, options)
      @aasm.instance_eval(&block) if block # new DSL
      @aasm
    end

    # TODO: maybe better: aasm.initial_state
    def aasm_initial_state(set_state=nil)
      if set_state
        # deprecated way to set the value
        AASM::StateMachine[self].initial_state = set_state
      else
        AASM::StateMachine[self].initial_state
      end
    end

    # is this better?: aasm.states.name.from_states
    def aasm_from_states_for_state(state, options={})
      if options[:transition]
        aasm.events[options[:transition]].transitions_to_state(state).flatten.map(&:from).flatten
      else
        aasm.events.map {|k,v| v.transitions_to_state(state)}.flatten.map(&:from).flatten
      end
    end

    # deprecated
    def aasm_initial_state=(state)
      AASM::StateMachine[self].initial_state = state
    end

    # deprecated
    def aasm_state(name, options={})
      aasm.state(name, options)
    end

    # deprecated
    def aasm_event(name, options = {}, &block)
      aasm.event(name, options, &block)
    end

    # deprecated
    def aasm_states
      aasm.states
    end

    # deprecated
    def aasm_events
      aasm.events
    end

    # deprecated
    def aasm_states_for_select
      aasm.states_for_select
    end

    # aasm.event(:event_name).human?
    def aasm_human_event_name(event) # event_name?
      AASM::Localizer.new.human_event_name(self, event)
    end
  end # ClassMethods

  def aasm
    @aasm ||= AASM::InstanceBase.new(self)
  end

  # may be overwritten by persistence mixins
  def aasm_read_state
    # all the following lines behave like @current_state ||= aasm.enter_initial_state
    current = aasm.instance_variable_get("@current_state")
    return current if current
    aasm.instance_variable_set("@current_state", aasm.enter_initial_state)
  end

  # may be overwritten by persistence mixins
  def aasm_write_state(new_state)
    true
  end

  # may be overwritten by persistence mixins
  def aasm_write_state_without_persistence(new_state)
    true
  end

  # deprecated
  def aasm_current_state
    # warn "#aasm_current_state is deprecated and will be removed in version 3.2.0; please use #aasm.state instead!"
    aasm.current_state
  end

  # deprecated
  def aasm_enter_initial_state
    # warn "#aasm_enter_initial_state is deprecated and will be removed in version 3.2.0; please use #aasm.enter_initial_state instead!"
    aasm.enter_initial_state
  end

  # deprecated
  def aasm_events_for_current_state
    # warn "#aasm_events_for_current_state is deprecated and will be removed in version 3.2.0; please use #aasm.events instead!"
    aasm.events(aasm.current_state)
  end

  # deprecated
  def aasm_permissible_events_for_current_state
    # warn "#aasm_permissible_events_for_current_state is deprecated and will be removed in version 3.2.0; please use #aasm.permissible_events instead!"
    aasm.permissible_events
  end

  # deprecated
  def aasm_events_for_state(state_name)
    # warn "#aasm_events_for_state(state_name) is deprecated and will be removed in version 3.2.0; please use #aasm.events(state_name) instead!"
    aasm.events(state_name)
  end

  # deprecated
  def aasm_human_state
    # warn "#aasm_human_state is deprecated and will be removed in version 3.2.0; please use #aasm.human_state instead!"
    aasm.human_state
  end

private

  def aasm_fire_event(event_name, options, *args)
    event = self.class.aasm_events[event_name]
    begin
      old_state = aasm.state_object_for_name(aasm.current_state)
      old_state.fire_callbacks(:exit, self)

      # new event before callback
      event.fire_callbacks(:before, self)

      if new_state_name = event.fire(self, *args)
        fired(event, old_state, new_state_name, options)
      else
        failed(event_name, old_state)
      end
    rescue StandardError => e
      event.fire_callbacks(:error, self, e) || raise(e)
    end
  end

  def fired(event, old_state, new_state_name, options)
    persist = options[:persist]

    new_state = aasm.state_object_for_name(new_state_name)

    # new before_ callbacks
    old_state.fire_callbacks(:before_exit, self)
    new_state.fire_callbacks(:before_enter, self)

    new_state.fire_callbacks(:enter, self)

    persist_successful = true
    if persist
      persist_successful = aasm.set_current_state_with_persistence(new_state_name)
      event.fire_callbacks(:success, self) if persist_successful
    else
      aasm.current_state = new_state_name
    end

    if persist_successful
      old_state.fire_callbacks(:after_exit, self)
      new_state.fire_callbacks(:after_enter, self)
      event.fire_callbacks(:after, self)

      self.aasm_event_fired(event.name, old_state.name, aasm.current_state) if self.respond_to?(:aasm_event_fired)
    else
      self.aasm_event_failed(event.name, old_state.name) if self.respond_to?(:aasm_event_failed)
    end

    persist_successful
  end

  def failed(event_name, old_state)
    if self.respond_to?(:aasm_event_failed)
      self.aasm_event_failed(event_name, old_state.name)
    end

    if AASM::StateMachine[self.class].config.whiny_transitions
      raise AASM::InvalidTransition, "Event '#{event_name}' cannot transition from '#{aasm.current_state}'"
    else
      false
    end
  end

end


================================================
FILE: lib/aasm/base.rb
================================================
module AASM
  class Base

    def initialize(clazz, options={}, &block)
      @clazz = clazz
      @state_machine = AASM::StateMachine[@clazz]
      @state_machine.config.column = options[:column].to_sym if options[:column]

      if options.key?(:whiny_transitions)
        @state_machine.config.whiny_transitions = options[:whiny_transitions]
      elsif @state_machine.config.whiny_transitions.nil?
        @state_machine.config.whiny_transitions = true # this is the default, so let's cry
      end

      if options.key?(:skip_validation_on_save)
        @state_machine.config.skip_validation_on_save = options[:skip_validation_on_save]
      elsif @state_machine.config.skip_validation_on_save.nil?
        @state_machine.config.skip_validation_on_save = false # this is the default, so don't store any new state if the model is invalid
      end
    end

    def initial_state
      @state_machine.initial_state
    end

    # define a state
    def state(name, options={})
      # @clazz.aasm_state(name, options)
      @state_machine.add_state(name, @clazz, options)
      @state_machine.initial_state = name if options[:initial] || !@state_machine.initial_state

      @clazz.send(:define_method, "#{name.to_s}?") do
        aasm.current_state == name
      end

      unless @clazz.const_defined?("STATE_#{name.to_s.upcase}")
        @clazz.const_set("STATE_#{name.to_s.upcase}", name)
      end
    end

    # define an event
    def event(name, options={}, &block)
      # @clazz.aasm_event(name, options, &block)

      unless @state_machine.events.has_key?(name)
        @state_machine.events[name] = AASM::Event.new(name, options, &block)
      end

      # an addition over standard aasm so that, before firing an event, you can ask
      # may_event? and get back a boolean that tells you whether the guard method
      # on the transition will let this happen.
      @clazz.send(:define_method, "may_#{name.to_s}?") do |*args|
        aasm.may_fire_event?(name, *args)
      end

      @clazz.send(:define_method, "#{name.to_s}!") do |*args|
        aasm_fire_event(name, {:persist => true}, *args)
      end

      @clazz.send(:define_method, "#{name.to_s}") do |*args|
        aasm_fire_event(name, {:persist => false}, *args)
      end
    end

    def states
      @state_machine.states
    end

    def events
      @state_machine.events
    end

    def states_for_select
      states.map { |state| state.for_select }
    end

  end
end


================================================
FILE: lib/aasm/deprecated/aasm.rb
================================================
module AASM

  module ClassMethods
    def human_event_name(*args)
      warn "AASM.human_event_name is deprecated and will be removed in version 3.1.0; please use AASM.aasm_human_event_name instead!"
      aasm_human_event_name(*args)
    end
  end

  def human_state
    warn "AASM#human_state is deprecated and will be removed in version 3.1.0; please use AASM#aasm_human_state instead!"
    aasm_human_state
  end

end


================================================
FILE: lib/aasm/errors.rb
================================================
module AASM
  class InvalidTransition < RuntimeError; end
  class UndefinedState < RuntimeError; end
end


================================================
FILE: lib/aasm/event.rb
================================================
module AASM
  class Event

    attr_reader :name, :options

    def initialize(name, options = {}, &block)
      @name = name
      @transitions = []
      update(options, &block)
    end

    # a neutered version of fire - it doesn't actually fire the event, it just
    # executes the transition guards to determine if a transition is even
    # an option given current conditions.
    def may_fire?(obj, to_state=nil, *args)
      _fire(obj, true, to_state, *args) # true indicates test firing
    end

    def fire(obj, to_state=nil, *args)
      _fire(obj, false, to_state, *args) # false indicates this is not a test (fire!)
    end

    def transitions_from_state?(state)
      transitions_from_state(state).any?
    end

    def transitions_from_state(state)
      @transitions.select { |t| t.from == state }
    end

    def transitions_to_state?(state)
      transitions_to_state(state).any?
    end

    def transitions_to_state(state)
      @transitions.select { |t| t.to == state }
    end

    # deprecated
    def all_transitions
      # warn "Event#all_transitions is deprecated and will be removed in version 3.2.0; please use Event#transitions instead!"
      transitions
    end

    def fire_callbacks(callback_name, record, *args)
      invoke_callbacks(@options[callback_name], record, args)
    end

    def ==(event)
      if event.is_a? Symbol
        name == event
      else
        name == event.name
      end
    end

  private

    def update(options = {}, &block)
      @options = options
      if block then
        instance_eval(&block)
      end
      self
    end

    # Execute if test == false, otherwise return true/false depending on whether it would fire
    def _fire(obj, test, to_state=nil, *args)
      result = test ? false : nil
      if @transitions.map(&:from).any?
        transitions = @transitions.select { |t| t.from == obj.aasm_current_state }
        return result if transitions.size == 0
      else
        transitions = @transitions
      end

      transitions.each do |transition|
        next if to_state and !Array(transition.to).include?(to_state)
        if transition.perform(obj, *args)
          if test
            result = true
          else
            result = to_state || Array(transition.to).first
            transition.execute(obj, *args)
          end

          break
        end
      end
      result
    end

    def invoke_callbacks(code, record, args)
      case code
        when Symbol, String
          record.send(code, *args)
          true
        when Proc
          record.instance_exec(*args, &code)
          true
        when Array
          code.each {|a| invoke_callbacks(a, record, args)}
          true
        else
          false
      end
    end

    ## DSL interface
    def transitions(trans_opts=nil)
      if trans_opts # define new transitions
        # Create a separate transition for each from state to the given state
        Array(trans_opts[:from]).each do |s|
          @transitions << AASM::Transition.new(trans_opts.merge({:from => s.to_sym}))
        end
        # Create a transition if to is specified without from (transitions from ANY state)
        @transitions << AASM::Transition.new(trans_opts) if @transitions.empty? && trans_opts[:to]
      end
      @transitions
    end

    [:after, :before, :error, :success].each do |callback_name|
      define_method callback_name do |*args, &block|
        options[callback_name] = Array(options[callback_name])
        options[callback_name] << block if block
        options[callback_name] += Array(args)
      end
    end
  end
end # AASM


================================================
FILE: lib/aasm/instance_base.rb
================================================
module AASM
  class InstanceBase

    def initialize(instance)
      @instance = instance
    end

    def current_state
      @instance.aasm_read_state
    end

    def current_state=(state)
      @instance.aasm_write_state_without_persistence(state)
      @current_state = state
    end

    def enter_initial_state
      state_name = determine_state_name(@instance.class.aasm_initial_state)
      state_object = state_object_for_name(state_name)

      state_object.fire_callbacks(:before_enter, @instance)
      state_object.fire_callbacks(:enter, @instance)
      self.current_state = state_name
      state_object.fire_callbacks(:after_enter, @instance)

      state_name
    end

    def human_state
      AASM::Localizer.new.human_state_name(@instance.class, current_state)
    end

    def states(options={})
      if options[:permissible]
        # ugliness level 1000
        transitions = @instance.class.aasm.events.values.map {|e| e.transitions_from_state(current_state) }
        tos = transitions.map {|t| t[0] ? t[0].to : nil}.flatten.compact.map(&:to_sym).uniq
        @instance.class.aasm.states.select {|s| tos.include?(s.name.to_sym)}
      else
        @instance.class.aasm.states
      end
    end

    # QUESTION: shouldn't events and permissible_events be the same thing?
    # QUESTION: shouldn't events return objects instead of strings?
    def events(state=current_state)
      events = @instance.class.aasm.events.values.select {|e| e.transitions_from_state?(state) }
      events.map {|e| e.name}
    end

    # filters the results of events_for_current_state so that only those that
    # are really currently possible (given transition guards) are shown.
    # QUESTION: what about events.permissible ?
    def permissible_events
      events.select{ |e| @instance.send(("may_" + e.to_s + "?").to_sym) }
    end

    def state_object_for_name(name)
      obj = @instance.class.aasm.states.find {|s| s == name}
      raise AASM::UndefinedState, "State :#{name} doesn't exist" if obj.nil?
      obj
    end

    def determine_state_name(state)
      case state
        when Symbol, String
          state
        when Proc
          state.call(@instance)
        else
          raise NotImplementedError, "Unrecognized state-type given.  Expected Symbol, String, or Proc."
      end
    end

    def may_fire_event?(name, *args)
      event = @instance.class.aasm.events[name]
      event.may_fire?(@instance, *args)
    end

    def set_current_state_with_persistence(state)
      save_success = @instance.aasm_write_state(state)
      self.current_state = state if save_success
      save_success
    end

  end
end


================================================
FILE: lib/aasm/localizer.rb
================================================
module AASM
  class Localizer
    def human_event_name(klass, event)
      checklist = ancestors_list(klass).inject([]) do |list, ancestor|
        list << :"#{i18n_scope(klass)}.events.#{i18n_klass(ancestor)}.#{event}"
        list
      end
      translate_queue(checklist) || I18n.translate(checklist.shift, :default => event.to_s.humanize)
    end

    def human_state_name(klass, state)
      checklist = ancestors_list(klass).inject([]) do |list, ancestor|
        list << item_for(klass, state, ancestor)
        list << item_for(klass, state, ancestor, :old_style => true)
        list
      end
      translate_queue(checklist) || I18n.translate(checklist.shift, :default => state.to_s.humanize)
    end

  private

    def item_for(klass, state, ancestor, options={})
      separator = options[:old_style] ? '.' : '/'
      :"#{i18n_scope(klass)}.attributes.#{i18n_klass(ancestor)}.#{klass.aasm_column}#{separator}#{state}"
    end

    def translate_queue(checklist)
      (0...(checklist.size-1)).each do |i|
        begin
          return I18n.translate(checklist.shift, :raise => true)
        rescue I18n::MissingTranslationData
          # that's okay
        end
      end
      nil
    end

    # added for rails 2.x compatibility
    def i18n_scope(klass)
      klass.respond_to?(:i18n_scope) ? klass.i18n_scope : :activerecord
    end

    # added for rails < 3.0.3 compatibility
    def i18n_klass(klass)
      klass.model_name.respond_to?(:i18n_key) ? klass.model_name.i18n_key : klass.name.underscore
    end

    def ancestors_list(klass)
      klass.ancestors.select do |ancestor|
        ancestor.respond_to?(:model_name) unless ancestor == ActiveRecord::Base
      end
    end
  end
end # AASM


================================================
FILE: lib/aasm/persistence/active_record_persistence.rb
================================================
module AASM
  module Persistence
    module ActiveRecordPersistence
      # This method:
      #
      # * extends the model with ClassMethods
      # * includes InstanceMethods
      #
      # Adds
      #
      #   before_validation :aasm_ensure_initial_state, :on => :create
      #
      # As a result, it doesn't matter when you define your methods - the following 2 are equivalent
      #
      #   class Foo < ActiveRecord::Base
      #     def aasm_write_state(state)
      #       "bar"
      #     end
      #     include AASM
      #   end
      #
      #   class Foo < ActiveRecord::Base
      #     include AASM
      #     def aasm_write_state(state)
      #       "bar"
      #     end
      #   end
      #
      def self.included(base)
        base.send(:include, AASM::Persistence::Base)
        base.extend AASM::Persistence::ActiveRecordPersistence::ClassMethods
        base.send(:include, AASM::Persistence::ActiveRecordPersistence::InstanceMethods)

        if ActiveRecord::VERSION::MAJOR >= 3
          base.before_validation(:aasm_ensure_initial_state, :on => :create)
        else
          base.before_validation_on_create(:aasm_ensure_initial_state)
        end
      end

      module ClassMethods

        def find_in_state(number, state, *args)
          with_state_scope state do
            find(number, *args)
          end
        end

        def count_in_state(state, *args)
          with_state_scope state do
            count(*args)
          end
        end

        def calculate_in_state(state, *args)
          with_state_scope state do
            calculate(*args)
          end
        end

        protected
        def with_state_scope(state)
          with_scope :find => {:conditions => ["#{table_name}.#{aasm_column} = ?", state.to_s]} do
            yield if block_given?
          end
        end
      end

      module InstanceMethods

        # Writes <tt>state</tt> to the state column and persists it to the database
        #
        #   foo = Foo.find(1)
        #   foo.aasm_current_state # => :opened
        #   foo.close!
        #   foo.aasm_current_state # => :closed
        #   Foo.find(1).aasm_current_state # => :closed
        #
        # NOTE: intended to be called from an event
        def aasm_write_state(state)
          old_value = read_attribute(self.class.aasm_column)
          write_attribute(self.class.aasm_column, state.to_s)

          success = if AASM::StateMachine[self.class].config.skip_validation_on_save
            self.class.where(self.class.primary_key => self.id).update_all(self.class.aasm_column => state.to_s) == 1
          else
            self.save
          end
          unless success
            write_attribute(self.class.aasm_column, old_value)
            return false
          end

          true
        end

        # Writes <tt>state</tt> to the state column, but does not persist it to the database
        #
        #   foo = Foo.find(1)
        #   foo.aasm_current_state # => :opened
        #   foo.close
        #   foo.aasm_current_state # => :closed
        #   Foo.find(1).aasm_current_state # => :opened
        #   foo.save
        #   foo.aasm_current_state # => :closed
        #   Foo.find(1).aasm_current_state # => :closed
        #
        # NOTE: intended to be called from an event
        def aasm_write_state_without_persistence(state)
          write_attribute(self.class.aasm_column, state.to_s)
        end

      private

        # Ensures that if the aasm_state column is nil and the record is new
        # that the initial state gets populated before validation on create
        #
        #   foo = Foo.new
        #   foo.aasm_state # => nil
        #   foo.valid?
        #   foo.aasm_state # => "open" (where :open is the initial state)
        #
        #
        #   foo = Foo.find(:first)
        #   foo.aasm_state # => 1
        #   foo.aasm_state = nil
        #   foo.valid?
        #   foo.aasm_state # => nil
        #
        def aasm_ensure_initial_state
          aasm.enter_initial_state if send(self.class.aasm_column).blank?
        end

        def aasm_fire_event(name, options, *args)
          transaction do
            super
          end
        end
      end # InstanceMethods

    end
  end
end


================================================
FILE: lib/aasm/persistence/base.rb
================================================
module AASM
  module Persistence
    module Base

      def self.included(base) #:nodoc:
        base.extend ClassMethods
      end

      # Returns the value of the aasm_column - called from <tt>aasm.current_state</tt>
      #
      # If it's a new record, and the aasm state column is blank it returns the initial state
      # (example provided here for ActiveRecord, but it's true for Mongoid as well):
      #
      #   class Foo < ActiveRecord::Base
      #     include AASM
      #     aasm :column => :status do
      #       state :opened
      #       state :closed
      #     end
      #   end
      #
      #   foo = Foo.new
      #   foo.current_state # => :opened
      #   foo.close
      #   foo.current_state # => :closed
      #
      #   foo = Foo.find(1)
      #   foo.current_state # => :opened
      #   foo.aasm_state = nil
      #   foo.current_state # => nil
      #
      # NOTE: intended to be called from an event
      #
      # This allows for nil aasm states - be sure to add validation to your model
      def aasm_read_state
        state = send(self.class.aasm_column)
        if new_record?
          state.blank? ? aasm.determine_state_name(self.class.aasm_initial_state) : state.to_sym
        else
          state.nil? ? nil : state.to_sym
        end
      end

      module ClassMethods
        # Maps to the aasm_column in the database.  Defaults to "aasm_state".  You can write
        # (example provided here for ActiveRecord, but it's true for Mongoid as well):
        #
        #   create_table :foos do |t|
        #     t.string :name
        #     t.string :aasm_state
        #   end
        #
        #   class Foo < ActiveRecord::Base
        #     include AASM
        #   end
        #
        # OR:
        #
        #   create_table :foos do |t|
        #     t.string :name
        #     t.string :status
        #   end
        #
        #   class Foo < ActiveRecord::Base
        #     include AASM
        #     aasm_column :status
        #   end
        #
        # This method is both a getter and a setter
        def aasm_column(column_name=nil)
          if column_name
            AASM::StateMachine[self].config.column = column_name.to_sym
            # @aasm_column = column_name.to_sym
          else
            AASM::StateMachine[self].config.column ||= :aasm_state
            # @aasm_column ||= :aasm_state
          end
          # @aasm_column
          AASM::StateMachine[self].config.column
        end
      end # ClassMethods

    end # Base
  end # Persistence

  class Base
    # make sure to create a (named) scope for each state
    def state_with_scope(name, *args)
      state_without_scope(name, *args)
      unless @clazz.respond_to?(name)
        if @clazz.ancestors.map {|klass| klass.to_s}.include?("ActiveRecord::Base")

          conditions = {"#{@clazz.table_name}.#{@clazz.aasm_column}" => name.to_s}
          if ActiveRecord::VERSION::MAJOR >= 4
            @clazz.class_eval do
              scope name, lambda { where(conditions) }
            end
          elsif ActiveRecord::VERSION::MAJOR >= 3
            @clazz.class_eval do
              scope name, where(conditions)
            end
          else
            @clazz.class_eval do
              named_scope name, :conditions => conditions
            end
          end
        elsif @clazz.ancestors.map {|klass| klass.to_s}.include?("Mongoid::Document")
          scope_options = lambda { @clazz.send(:where, {@clazz.aasm_column.to_sym => name.to_s}) }
          @clazz.send(:scope, name, scope_options)
        end
      end
    end
    alias_method :state_without_scope, :state
    alias_method :state, :state_with_scope
  end # Base

end # AASM


================================================
FILE: lib/aasm/persistence/mongoid_persistence.rb
================================================
module AASM
  module Persistence
    module MongoidPersistence
      # This method:
      #
      # * extends the model with ClassMethods
      # * includes InstanceMethods
      #
      # Adds
      #
      #   before_validation :aasm_ensure_initial_state
      #
      # As a result, it doesn't matter when you define your methods - the following 2 are equivalent
      #
      #   class Foo
      #     include Mongoid::Document
      #     def aasm_write_state(state)
      #       "bar"
      #     end
      #     include AASM
      #   end
      #
      #   class Foo
      #     include Mongoid::Document
      #     include AASM
      #     def aasm_write_state(state)
      #       "bar"
      #     end
      #   end
      #
      def self.included(base)
        base.send(:include, AASM::Persistence::Base)
        base.extend AASM::Persistence::MongoidPersistence::ClassMethods
        base.send(:include, AASM::Persistence::MongoidPersistence::InstanceMethods)

        # Mongoid's Validatable gem dependency goes not have a before_validation_on_xxx hook yet.
        # base.before_validation_on_create :aasm_ensure_initial_state
        base.before_validation :aasm_ensure_initial_state
      end

      module ClassMethods

        def find_in_state(number, state, *args)
          with_state_scope state do
            find(number, *args)
          end
        end

        def count_in_state(state, *args)
          with_state_scope state do
            count(*args)
          end
        end

        def with_state_scope(state)
          with_scope where(aasm_column.to_sym => state.to_s) do
            yield if block_given?
          end
        end

      end

      module InstanceMethods

        # Writes <tt>state</tt> to the state column and persists it to the database
        # using update_attribute (which bypasses validation)
        #
        #   foo = Foo.find(1)
        #   foo.aasm_current_state # => :opened
        #   foo.close!
        #   foo.aasm_current_state # => :closed
        #   Foo.find(1).aasm_current_state # => :closed
        #
        # NOTE: intended to be called from an event
        def aasm_write_state(state)
          old_value = read_attribute(self.class.aasm_column)
          write_attribute(self.class.aasm_column, state.to_s)

          unless self.save(:validate => false)
            write_attribute(self.class.aasm_column, old_value)
            return false
          end

          true
        end

        # Writes <tt>state</tt> to the state column, but does not persist it to the database
        #
        #   foo = Foo.find(1)
        #   foo.aasm_current_state # => :opened
        #   foo.close
        #   foo.aasm_current_state # => :closed
        #   Foo.find(1).aasm_current_state # => :opened
        #   foo.save
        #   foo.aasm_current_state # => :closed
        #   Foo.find(1).aasm_current_state # => :closed
        #
        # NOTE: intended to be called from an event
        def aasm_write_state_without_persistence(state)
          write_attribute(self.class.aasm_column, state.to_s)
        end

      private

        # Ensures that if the aasm_state column is nil and the record is new
        # that the initial state gets populated before validation on create
        #
        #   foo = Foo.new
        #   foo.aasm_state # => nil
        #   foo.valid?
        #   foo.aasm_state # => "open" (where :open is the initial state)
        #
        #
        #   foo = Foo.find(:first)
        #   foo.aasm_state # => 1
        #   foo.aasm_state = nil
        #   foo.valid?
        #   foo.aasm_state # => nil
        #
        def aasm_ensure_initial_state
          send("#{self.class.aasm_column}=", aasm.enter_initial_state.to_s) if send(self.class.aasm_column).blank?
        end
      end # InstanceMethods

      module NamedScopeMethods
        def aasm_state_with_named_scope name, options = {}
          aasm_state_without_named_scope name, options
          self.named_scope name, :conditions => { "#{table_name}.#{self.aasm_column}" => name.to_s} unless self.respond_to?(name)
        end
      end
    end
  end
end


================================================
FILE: lib/aasm/persistence.rb
================================================
module AASM
  module Persistence
    class << self

      def load_persistence(base)
        # Use a fancier auto-loading thingy, perhaps.  When there are more persistence engines.
        hierarchy = base.ancestors.map {|klass| klass.to_s}

        if hierarchy.include?("ActiveRecord::Base")
          require_files_for(:active_record)
          base.send(:include, AASM::Persistence::ActiveRecordPersistence)
        elsif hierarchy.include?("Mongoid::Document")
          require_files_for(:mongoid)
          base.send(:include, AASM::Persistence::MongoidPersistence)
        end
      end

    private

      def require_files_for(persistence)
        ['base', "#{persistence}_persistence"].each do |file_name|
          require File.join(File.dirname(__FILE__), 'persistence', file_name)
        end
      end

    end # class << self
  end
end # AASM


================================================
FILE: lib/aasm/state.rb
================================================
module AASM
  class State
    attr_reader :name, :options

    def initialize(name, clazz, options={})
      @name = name
      @clazz = clazz
      update(options)
    end

    def ==(state)
      if state.is_a? Symbol
        name == state
      else
        name == state.name
      end
    end

    def <=>(state)
      if state.is_a? Symbol
        name <=> state
      else
        name <=> state.name
      end
    end

    def to_s
      name.to_s
    end

    def fire_callbacks(action, record)
      action = @options[action]
      catch :halt_aasm_chain do
        action.is_a?(Array) ?
                action.each {|a| _fire_callbacks(a, record)} :
                _fire_callbacks(action, record)
      end
    end

    def display_name
      @display_name ||= begin
        if Module.const_defined?(:I18n)
          localized_name
        else
          name.to_s.gsub(/_/, ' ').capitalize
        end
      end
    end

    def localized_name
      AASM::Localizer.new.human_state_name(@clazz, self)
    end

    def for_select
      [display_name, name.to_s]
    end

  private

    def update(options = {})
      if options.key?(:display) then
        @display_name = options.delete(:display)
      end
      @options = options
      self
    end

    def _fire_callbacks(action, record)
      case action
        when Symbol, String
          record.send(action)
        when Proc
          action.call(record)
      end
    end

  end
end # AASM


================================================
FILE: lib/aasm/state_machine.rb
================================================
module AASM
  class StateMachine

    # the following two methods provide the storage of all state machines
    def self.[](clazz)
      (@machines ||= {})[clazz.to_s]
    end

    def self.[]=(clazz, machine)
      (@machines ||= {})[clazz.to_s] = machine
    end

    attr_accessor :states, :events, :initial_state, :config
    attr_reader :name

    # QUESTION: what's the name for? [alto, 2012-11-28]
    def initialize(name)
      @name = name
      @initial_state = nil
      @states = []
      @events = {}
      @config = OpenStruct.new
    end

    # called internally by Ruby 1.9 after clone()
    def initialize_copy(orig)
      super
      @states = @states.dup
      @events = @events.dup
    end

    def add_state(name, clazz, options)
      @states << AASM::State.new(name, clazz, options) unless @states.include?(name)
    end

  end # StateMachine
end # AASM


================================================
FILE: lib/aasm/transition.rb
================================================
module AASM
  class Transition
    attr_reader :from, :to, :opts
    alias_method :options, :opts

    def initialize(opts)
      @from, @to, @guard, @on_transition = opts[:from], opts[:to], opts[:guard], opts[:on_transition]
      @opts = opts
    end

    # TODO: should be named allowed? or similar
    def perform(obj, *args)
      case @guard
        when Symbol, String
          obj.send(@guard, *args)
        when Proc
          @guard.call(obj, *args)
        else
          true
      end
    end

    def execute(obj, *args)
      @on_transition.is_a?(Array) ?
              @on_transition.each {|ot| _execute(obj, ot, *args)} :
              _execute(obj, @on_transition, *args)
    end

    def ==(obj)
      @from == obj.from && @to == obj.to
    end

    def from?(value)
      @from == value
    end

    private

    def _execute(obj, on_transition, *args)
      case on_transition
      when Proc
        on_transition.arity == 0 ? on_transition.call : on_transition.call(obj, *args)
      when Symbol, String
        obj.send(:method, on_transition.to_sym).arity == 0 ? obj.send(on_transition) : obj.send(on_transition, *args)
      end
    end

  end
end # AASM


================================================
FILE: lib/aasm/version.rb
================================================
module AASM
  VERSION = "3.0.19"
end


================================================
FILE: lib/aasm.rb
================================================
require 'ostruct'

%w(
    version
    errors
    base
    instance_base
    transition
    event
    state
    localizer
    state_machine
    persistence
    aasm
  ).each { |file| require File.join(File.dirname(__FILE__), 'aasm', file) }

# load the deprecated methods and modules
Dir[File.join(File.dirname(__FILE__), 'aasm', 'deprecated', '*.rb')].sort.each { |f| require File.expand_path(f) }


================================================
FILE: spec/database.yml
================================================
sqlite3:
  adapter: sqlite3
  database: spec/aasm.sqlite3.db


================================================
FILE: spec/en.yml
================================================
en:
  activerecord:
    events:
      localizer_test_model:
        close: "Let's close it!"

    attributes:
      localizer_test_model:
        aasm_state/opened: "It's open now!"


================================================
FILE: spec/en_deprecated_style.yml
================================================
en:
  activerecord:
    events:
      localizer_test_model:
        close: "Let's close it!"

    attributes:
      localizer_test_model:
        aasm_state:
          opened: "It's open now!"


================================================
FILE: spec/models/active_record/api.rb
================================================
class DefaultState
  attr_accessor :transient_store, :persisted_store
  include AASM
  aasm do
    state :alpha, :initial => true
    state :beta
    state :gamma
    event :release do
      transitions :from => [:alpha, :beta, :gamma], :to => :beta
    end
  end
end

class ProvidedState
  attr_accessor :transient_store, :persisted_store
  include AASM
  aasm do
    state :alpha, :initial => true
    state :beta
    state :gamma
    event :release do
      transitions :from => [:alpha, :beta, :gamma], :to => :beta
    end
  end

  def aasm_read_state
    :beta
  end

  def aasm_write_state(new_state)
    @persisted_store = new_state
  end

  def aasm_write_state_without_persistence(new_state)
    @transient_store = new_state
  end
end

class PersistedState < ActiveRecord::Base
  attr_accessor :transient_store, :persisted_store
  include AASM
  aasm do
    state :alpha, :initial => true
    state :beta
    state :gamma
    event :release do
      transitions :from => [:alpha, :beta, :gamma], :to => :beta
    end
  end
end

class ProvidedAndPersistedState < ActiveRecord::Base
  attr_accessor :transient_store, :persisted_store
  include AASM
  aasm do
    state :alpha, :initial => true
    state :beta
    state :gamma
    event :release do
      transitions :from => [:alpha, :beta, :gamma], :to => :beta
    end
  end

  def aasm_read_state
    :gamma
  end

  def aasm_write_state(new_state)
    @persisted_store = new_state
  end

  def aasm_write_state_without_persistence(new_state)
    @transient_store = new_state
  end
end


================================================
FILE: spec/models/argument.rb
================================================
class Argument
  include AASM
  aasm do
    state :invalid, :initial => true
    state :valid

    event :valid do
      transitions :to => :valid, :from => [:invalid]
    end
  end
end


================================================
FILE: spec/models/auth_machine.rb
================================================
class AuthMachine
  include AASM

  attr_accessor :activation_code, :activated_at, :deleted_at

  aasm do
    state :passive
    state :pending, :initial => true, :enter => :make_activation_code
    state :active,  :enter => :do_activate
    state :suspended
    state :deleted, :enter => :do_delete, :exit => :do_undelete
    state :waiting

    event :register do
      transitions :from => :passive, :to => :pending, :guard => Proc.new {|u| u.can_register? }
    end

    event :activate do
      transitions :from => :pending, :to => :active
    end

    event :suspend do
      transitions :from => [:passive, :pending, :active], :to => :suspended
    end

    event :delete do
      transitions :from => [:passive, :pending, :active, :suspended], :to => :deleted
    end

    # a dummy event that can never happen
    event :unpassify do
      transitions :from => :passive, :to => :active, :guard => Proc.new {|u| false }
    end

    event :unsuspend do
      transitions :from => :suspended, :to => :active,  :guard => Proc.new {|u| u.has_activated? }
      transitions :from => :suspended, :to => :pending, :guard => Proc.new {|u| u.has_activation_code? }
      transitions :from => :suspended, :to => :passive
    end

    event :wait do
      transitions :from => :suspended, :to => :waiting, :guard => :if_polite?
    end
  end

  def initialize
    # the AR backend uses a before_validate_on_create :aasm_ensure_initial_state
    # lets do something similar here for testing purposes.
    aasm.enter_initial_state
  end

  def make_activation_code
    @activation_code = 'moo'
  end

  def do_activate
    @activated_at = Time.now
    @activation_code = nil
  end

  def do_delete
    @deleted_at = Time.now
  end

  def do_undelete
    @deleted_at = false
  end

  def can_register?
    true
  end

  def has_activated?
    !!@activated_at
  end

  def has_activation_code?
    !!@activation_code
  end

  def if_polite?(phrase = nil)
    phrase == :please
  end
end


================================================
FILE: spec/models/bar.rb
================================================
class Bar
  include AASM

  aasm do
    state :read
    state :ended

    event :foo do
      transitions :to => :ended, :from => [:read]
    end
  end
end

class Baz < Bar
end


================================================
FILE: spec/models/callback_new_dsl.rb
================================================
class CallbackNewDsl
  include AASM

  aasm do
    state :open, :initial => true,
      :before_enter => :before_enter_open,
      :after_enter  => :after_enter_open,
      :before_exit  => :before_exit_open,
      :exit         => :exit_open,
      :after_exit   => :after_exit_open

    state :closed,
      :before_enter => :before_enter_closed,
      :enter        => :enter_closed,
      :after_enter  => :after_enter_closed,
      :before_exit  => :before_exit_closed,
      :after_exit   => :after_exit_closed

    event :close, :before => :before, :after => :after do
      transitions :to => :closed, :from => [:open]
    end

    event :open, :before => :before, :after => :after do
      transitions :to => :open, :from => :closed
    end
  end

  def before_enter_open; end
  def before_exit_open; end
  def after_enter_open; end
  def after_exit_open; end

  def before_enter_closed; end
  def before_exit_closed; end
  def after_enter_closed; end
  def after_exit_closed; end

  def before; end
  def after; end

  def enter_closed; end
  def exit_open; end
end


================================================
FILE: spec/models/callback_old_dsl.rb
================================================
class CallbackOldDsl
  include AASM

  aasm_initial_state :open
  aasm_state :open,
    :before_enter => :before_enter_open,
    :after_enter  => :after_enter_open,
    :before_exit  => :before_exit_open,
    :exit         => :exit_open,
    :after_exit   => :after_exit_open
  aasm_state :closed,
    :before_enter => :before_enter_closed,
    :enter        => :enter_closed,
    :after_enter  => :after_enter_closed,
    :before_exit  => :before_exit_closed,
    :after_exit   => :after_exit_closed

  aasm_event :close, :before => :before, :after => :after do
    transitions :to => :closed, :from => [:open]
  end

  aasm_event :open, :before => :before, :after => :after do
    transitions :to => :open, :from => :closed
  end

  def before_enter_open; end
  def before_exit_open; end
  def after_enter_open; end
  def after_exit_open; end

  def before_enter_closed; end
  def before_exit_closed; end
  def after_enter_closed; end
  def after_exit_closed; end

  def before; end
  def after; end

  def enter_closed; end
  def exit_open; end
end


================================================
FILE: spec/models/conversation.rb
================================================
class Conversation
  include AASM

  aasm do
    state :needs_attention, :initial => true
    state :read
    state :closed
    state :awaiting_response
    state :junk

    event :new_message do
    end

    event :view do
      transitions :to => :read, :from => [:needs_attention]
    end

    event :reply do
    end

    event :close do
      transitions :to => :closed, :from => [:read, :awaiting_response]
    end

    event :junk do
      transitions :to => :junk, :from => [:read]
    end

    event :unjunk do
    end
  end

  def initialize(persister)
    @persister = persister
  end


  private
  def aasm_read_state
    @persister.read_state
  end

  def aasm_write_state(state)
    @persister.write_state(state)
  end

end


================================================
FILE: spec/models/father.rb
================================================
require 'active_record'

class Father < ActiveRecord::Base
  include AASM

  aasm do
    state :missing_details, :initial => true
    state :pending_details_confirmation

    event :add_details do
      transitions :from => :missing_details, :to => :pending_details_confirmation
    end
  end

  def update_state
     if may_add_details?
       add_details!
     end
  end

end


================================================
FILE: spec/models/foo.rb
================================================
class Foo
  include AASM
  aasm do
    state :open, :initial => true, :exit => :exit
    state :closed, :enter => :enter

    event :close, :success => :success_callback do
      transitions :from => [:open], :to => [:closed]
    end

    event :null do
      transitions :from => [:open], :to => :closed, :guard => :always_false
    end
  end

  def always_false
    false
  end

  def success_callback
  end

  def enter
  end
  def exit
  end
end

class FooTwo < Foo
  include AASM
  aasm do
    state :foo
  end
end


================================================
FILE: spec/models/invalid_persistor.rb
================================================
require 'active_record'

class InvalidPersistor < ActiveRecord::Base
  include AASM
  aasm :column => :status, :skip_validation_on_save => true do
    state :sleeping, :initial => true
    state :running
    event :run do
      transitions :to => :running, :from => :sleeping
    end
    event :sleep do
      transitions :to => :sleeping, :from => :running
    end
  end
  validates_presence_of :name
end


================================================
FILE: spec/models/mongoid/simple_mongoid.rb
================================================
class SimpleMongoid
  include Mongoid::Document
  include AASM

  field :status, type: String

  aasm_column :status
  aasm_state :unknown_scope
  aasm_state :new
end


================================================
FILE: spec/models/mongoid/simple_new_dsl_mongoid.rb
================================================
class SimpleNewDslMongoid
  include Mongoid::Document
  include AASM

  field :status, type: String

  aasm :column => :status
  aasm do
    state :unknown_scope
    state :new
  end
end


================================================
FILE: spec/models/not_auto_loaded/process.rb
================================================
module Models
  class Process
    include AASM

    aasm_state :sleeping
    aasm_state :running
    aasm_state :suspended

    aasm_event :start do
      transitions :from => :sleeping, :to => :running
    end

    aasm_event :stop do
      transitions :from => :running, :to => :suspended
    end

  end
end



================================================
FILE: spec/models/parametrised_event.rb
================================================
class ParametrisedEvent
  include AASM
  aasm do
    state :sleeping, :initial => true
    state :showering
    state :working
    state :dating
    state :prettying_up

    event :wakeup do
      transitions :from => :sleeping, :to => [:showering, :working]
    end

    event :dress do
      transitions :from => :sleeping, :to => :working, :on_transition => :wear_clothes
      transitions :from => :showering, :to => [:working, :dating], :on_transition => Proc.new { |obj, *args| obj.wear_clothes(*args) }
      transitions :from => :showering, :to => :prettying_up, :on_transition => [:condition_hair, :fix_hair]
    end
  end

  def wear_clothes(shirt_color, trouser_type)
  end

  def condition_hair
  end

  def fix_hair
  end
end


================================================
FILE: spec/models/persistence.rb
================================================
class Gate < ActiveRecord::Base
  include AASM

  # Fake this column for testing purposes
  attr_accessor :aasm_state

  aasm do
    state :opened
    state :closed

    event :view do
      transitions :to => :read, :from => [:needs_attention]
    end
  end
end

class Reader < ActiveRecord::Base
  include AASM

  def aasm_read_state
    "fi"
  end
end

class Writer < ActiveRecord::Base
  def aasm_write_state(state)
    "fo"
  end
  include AASM
end

class Transient < ActiveRecord::Base
  def aasm_write_state_without_persistence(state)
    "fum"
  end
  include AASM
end

class Simple < ActiveRecord::Base
  include AASM
  aasm_column :status
  aasm_state :unknown_scope
  aasm_state :new
end

class SimpleNewDsl < ActiveRecord::Base
  include AASM
  aasm :column => :status
  aasm do
    state :unknown_scope
    state :new
  end
end

class Derivate < Simple
end

class DerivateNewDsl < SimpleNewDsl
end

class Thief < ActiveRecord::Base
  if ActiveRecord::VERSION::MAJOR >= 3
    self.table_name = 'thieves'
  else
    set_table_name "thieves"
  end
  include AASM
  aasm_initial_state  Proc.new { |thief| thief.skilled ? :rich : :jailed }
  aasm_state          :rich
  aasm_state          :jailed
  attr_accessor :skilled, :aasm_state
end


================================================
FILE: spec/models/process_with_new_dsl.rb
================================================
class ProcessWithNewDsl
  include AASM

  def self.state(*args)
    raise "wrong state method"
  end

  attr_accessor :flagged

  aasm do
    state :sleeping, :initial => true
    state :running, :after_enter => :flag
    state :suspended

    event :start do
      transitions :from => :sleeping, :to => :running
    end
    event :stop do
      transitions :from => :running, :to => :suspended
    end
  end

  def flag
    self.flagged = true
  end

  def self.event(*args)
    raise "wrong event method"
  end

end


================================================
FILE: spec/models/silencer.rb
================================================
class Silencer
  include AASM

  aasm :whiny_transitions => false do
    state :silent, :initial => true
    state :crying
    state :smiling

    event :cry do
      transitions :from => :silent, :to => :crying
    end

    event :smile do
      transitions :from => :crying, :to => :smiling
    end

    event :smile_any do
      transitions :to => :smiling
    end
  end

end


================================================
FILE: spec/models/son.rb
================================================
class Son < Father
  include AASM
end


================================================
FILE: spec/models/sub_classing.rb
================================================
class SubClassing < Silencer
  
end

================================================
FILE: spec/models/this_name_better_not_be_in_use.rb
================================================
class ThisNameBetterNotBeInUse
  include AASM

  aasm do
    state :initial
    state :symbol
    state :string
    state :array
    state :proc
  end
end


================================================
FILE: spec/models/transactor.rb
================================================
require 'active_record'
class Transactor < ActiveRecord::Base

  belongs_to :worker

  include AASM
  aasm :column => :status do
    state :sleeping, :initial => true
    state :running, :before_enter => :start_worker, :after_enter => :fail

    event :run do
      transitions :to => :running, :from => :sleeping
    end
  end

private

  def start_worker
    worker.update_attribute(:status, 'running')
  end

  def fail
    raise StandardError.new('failed on purpose')
  end

end


================================================
FILE: spec/models/validator.rb
================================================
require 'active_record'

class Validator < ActiveRecord::Base
  include AASM
  aasm :column => :status do
    state :sleeping, :initial => true
    state :running
    event :run do
      transitions :to => :running, :from => :sleeping
    end
    event :sleep do
      transitions :to => :sleeping, :from => :running
    end
  end
  validates_presence_of :name
end


================================================
FILE: spec/models/worker.rb
================================================
class Worker < ActiveRecord::Base
end


================================================
FILE: spec/schema.rb
================================================
ActiveRecord::Schema.define(:version => 0) do

  %w{gates readers writers transients simples simple_new_dsls thieves localizer_test_models persisted_states provided_and_persisted_states}.each do |table_name|
    create_table table_name, :force => true do |t|
      t.string "aasm_state"
    end
  end

  create_table "validators", :force => true do |t|
    t.string "name"
    t.string "status"
  end

  create_table "transactors", :force => true do |t|
    t.string "name"
    t.string "status"
    t.integer "worker_id"
  end

  create_table "workers", :force => true do |t|
    t.string "name"
    t.string "status"
  end

  create_table "invalid_persistors", :force => true do |t|
    t.string "name"
    t.string "status"
  end

  create_table "fathers", :force => true do |t|
    t.string "aasm_state"
    t.string "type"
  end

end


================================================
FILE: spec/spec_helper.rb
================================================
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
$LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
require 'aasm'

require 'rspec'
require 'rspec/autorun'

require 'coveralls'
Coveralls.wear!

# require 'ruby-debug'; Debugger.settings[:autoeval] = true; debugger; rubys_debugger = 'annoying'
# require 'ruby-debug/completion'
# require 'pry'

def load_schema
  config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
  ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
  ActiveRecord::Base.establish_connection(config['sqlite3'])
  load(File.dirname(__FILE__) + "/schema.rb")
end

# custom spec helpers
Dir[File.dirname(__FILE__) + "/spec_helpers/**/*.rb"].sort.each { |f| require File.expand_path(f) }

# example model classes
Dir[File.dirname(__FILE__) + "/models/*.rb"].sort.each { |f| require File.expand_path(f) }


================================================
FILE: spec/unit/api_spec.rb
================================================
require 'spec_helper'
require 'models/active_record/api.rb'

describe "reading the current state" do
  it "uses the AASM default" do
    DefaultState.new.aasm.current_state.should eql :alpha
  end

  it "uses the provided method" do
    ProvidedState.new.aasm.current_state.should eql :beta
  end

  it "uses the persistence storage" do
    PersistedState.new.aasm.current_state.should eql :alpha
  end

  it "uses the provided method even if persisted" do
    ProvidedAndPersistedState.new.aasm.current_state.should eql :gamma
  end
end

describe "writing and persisting the current state" do
  it "uses the AASM default" do
    o = DefaultState.new
    o.release!
    o.persisted_store.should be_nil
  end

  it "uses the provided method" do
    o = ProvidedState.new
    o.release!
    o.persisted_store.should eql :beta
  end

  it "uses the persistence storage" do
    o = PersistedState.new
    o.release!
    o.persisted_store.should be_nil
  end

  it "uses the provided method even if persisted" do
    o = ProvidedAndPersistedState.new
    o.release!
    o.persisted_store.should eql :beta
  end
end

describe "writing the current state without persisting it" do
  it "uses the AASM default" do
    o = DefaultState.new
    o.release
    o.transient_store.should be_nil
  end

  it "uses the provided method" do
    o = ProvidedState.new
    o.release
    o.transient_store.should eql :beta
  end

  it "uses the persistence storage" do
    o = PersistedState.new
    o.release
    o.transient_store.should be_nil
  end

  it "uses the provided method even if persisted" do
    o = ProvidedAndPersistedState.new
    o.release
    o.transient_store.should eql :beta
  end
end


================================================
FILE: spec/unit/callbacks_spec.rb
================================================
require 'spec_helper'

describe 'callbacks for the old DSL' do
  let(:callback) {CallbackOldDsl.new}

  it "should get close callbacks" do
    callback.should_receive(:exit_open).once.ordered
    callback.should_receive(:before).once.ordered
    callback.should_receive(:before_exit_open).once.ordered                   # these should be before the state changes
    callback.should_receive(:before_enter_closed).once.ordered
    callback.should_receive(:enter_closed).once.ordered
    callback.should_receive(:aasm_write_state).once.ordered.and_return(true)  # this is when the state changes
    callback.should_receive(:after_exit_open).once.ordered                    # these should be after the state changes
    callback.should_receive(:after_enter_closed).once.ordered
    callback.should_receive(:after).once.ordered

    callback.close!
  end
end

describe 'callbacks for the new DSL' do
  let(:callback) {CallbackNewDsl.new}

  it "be called in order" do
    callback.should_receive(:exit_open).once.ordered
    callback.should_receive(:before).once.ordered
    callback.should_receive(:before_exit_open).once.ordered                   # these should be before the state changes
    callback.should_receive(:before_enter_closed).once.ordered
    callback.should_receive(:enter_closed).once.ordered
    callback.should_receive(:aasm_write_state).once.ordered.and_return(true)  # this is when the state changes
    callback.should_receive(:after_exit_open).once.ordered                    # these should be after the state changes
    callback.should_receive(:after_enter_closed).once.ordered
    callback.should_receive(:after).once.ordered

    callback.close!
  end
end

describe 'event callbacks' do
  describe "with an error callback defined" do
    before do
      class Foo
        aasm_event :safe_close, :success => :success_callback, :error => :error_callback do
          transitions :to => :closed, :from => [:open]
        end
      end

      @foo = Foo.new
    end

    it "should run error_callback if an exception is raised and error_callback defined" do
      def @foo.error_callback(e); end

      @foo.stub!(:enter).and_raise(e=StandardError.new)
      @foo.should_receive(:error_callback).with(e)

      @foo.safe_close!
    end

    it "should raise NoMethodError if exceptionis raised and error_callback is declared but not defined" do
      @foo.stub!(:enter).and_raise(StandardError)
      lambda{@foo.safe_close!}.should raise_error(NoMethodError)
    end

    it "should propagate an error if no error callback is declared" do
        @foo.stub!(:enter).and_raise("Cannot enter safe")
        lambda{@foo.close!}.should raise_error(StandardError, "Cannot enter safe")
    end
  end

  describe "with aasm_event_fired defined" do
    before do
      @foo = Foo.new
      def @foo.aasm_event_fired(event, from, to); end
    end

    it 'should call it for successful bang fire' do
      @foo.should_receive(:aasm_event_fired).with(:close, :open, :closed)
      @foo.close!
    end

    it 'should call it for successful non-bang fire' do
      @foo.should_receive(:aasm_event_fired)
      @foo.close
    end

    it 'should not call it for failing bang fire' do
      @foo.aasm.stub!(:set_current_state_with_persistence).and_return(false)
      @foo.should_not_receive(:aasm_event_fired)
      @foo.close!
    end
  end

  describe "with aasm_event_failed defined" do
    before do
      @foo = Foo.new
      def @foo.aasm_event_failed(event, from); end
    end

    it 'should call it when transition failed for bang fire' do
      @foo.should_receive(:aasm_event_failed).with(:null, :open)
      lambda {@foo.null!}.should raise_error(AASM::InvalidTransition)
    end

    it 'should call it when transition failed for non-bang fire' do
      @foo.should_receive(:aasm_event_failed).with(:null, :open)
      lambda {@foo.null}.should raise_error(AASM::InvalidTransition)
    end

    it 'should not call it if persist fails for bang fire' do
      @foo.aasm.stub!(:set_current_state_with_persistence).and_return(false)
      @foo.should_receive(:aasm_event_failed)
      @foo.close!
    end
  end
end


================================================
FILE: spec/unit/complex_example_spec.rb
================================================
require 'spec_helper'

describe 'on initialization' do
  let(:auth) {AuthMachine.new}

  it 'should be in the pending state' do
    auth.aasm_current_state.should == :pending
  end

  it 'should have an activation code' do
    auth.has_activation_code?.should be_true
    auth.activation_code.should_not be_nil
  end
end

describe 'when being unsuspended' do
  let(:auth) {AuthMachine.new}

  it 'should be able to be unsuspended' do
    auth.activate!
    auth.suspend!
    auth.may_unsuspend?.should be_true
  end

  it 'should not be able to be unsuspended into active' do
    auth.suspend!
    auth.may_unsuspend?(:active).should_not be_true
  end

  it 'should be able to be unsuspended into active if polite' do
    auth.suspend!
    auth.may_wait?(:waiting, :please).should be_true
    auth.wait!(nil, :please)
  end

  it 'should not be able to be unsuspended into active if not polite' do
    auth.suspend!
    auth.may_wait?(:waiting).should_not be_true
    auth.may_wait?(:waiting, :rude).should_not be_true
    lambda {auth.wait!(nil, :rude)}.should raise_error(AASM::InvalidTransition)
    lambda {auth.wait!}.should raise_error(AASM::InvalidTransition)
  end

  it 'should not be able to be unpassified' do
    auth.activate!
    auth.suspend!
    auth.unsuspend!

    auth.may_unpassify?.should_not be_true
    lambda {auth.unpassify!}.should raise_error(AASM::InvalidTransition)
  end

  it 'should be active if previously activated' do
    auth.activate!
    auth.suspend!
    auth.unsuspend!

    auth.aasm_current_state.should == :active
  end

  it 'should be pending if not previously activated, but an activation code is present' do
    auth.suspend!
    auth.unsuspend!

    auth.aasm_current_state.should == :pending
  end

  it 'should be passive if not previously activated and there is no activation code' do
    auth.activation_code = nil
    auth.suspend!
    auth.unsuspend!

    auth.aasm_current_state.should == :passive
  end
end


================================================
FILE: spec/unit/event_spec.rb
================================================
require 'spec_helper'

describe 'adding an event' do
  let(:event) do
    AASM::Event.new(:close_order, {:success => :success_callback}) do
      before :before_callback
      after :after_callback
      transitions :to => :closed, :from => [:open, :received]
    end
  end

  it 'should set the name' do
    event.name.should == :close_order
  end

  it 'should set the success callback' do
    event.options[:success].should == :success_callback
  end

  it 'should set the after callback' do
    event.options[:after].should == [:after_callback]
  end

  it 'should set the before callback' do
    event.options[:before].should == [:before_callback]
  end

  it 'should create transitions' do
    transitions = event.all_transitions
    transitions[0].from.should == :open
    transitions[0].to.should == :closed
    transitions[1].from.should == :received
    transitions[1].to.should == :closed
  end
end

describe 'transition inspection' do
  let(:event) do
    AASM::Event.new(:run) do
      transitions :to => :running, :from => :sleeping
    end
  end

  it 'should support inspecting transitions from other states' do
    event.transitions_from_state(:sleeping).map(&:to).should == [:running]
    event.transitions_from_state?(:sleeping).should be_true

    event.transitions_from_state(:cleaning).map(&:to).should == []
    event.transitions_from_state?(:cleaning).should be_false
  end

  it 'should support inspecting transitions to other states' do
    event.transitions_to_state(:running).map(&:from).should == [:sleeping]
    event.transitions_to_state?(:running).should be_true

    event.transitions_to_state(:cleaning).map(&:to).should == []
    event.transitions_to_state?(:cleaning).should be_false
  end
end

describe 'firing an event' do
  it 'should return nil if the transitions are empty' do
    obj = mock('object')
    obj.stub!(:aasm_current_state)

    event = AASM::Event.new(:event)
    event.fire(obj).should be_nil
  end

  it 'should return the state of the first matching transition it finds' do
    event = AASM::Event.new(:event) do
      transitions :to => :closed, :from => [:open, :received]
    end

    obj = mock('object')
    obj.stub!(:aasm_current_state).and_return(:open)

    event.fire(obj).should == :closed
  end

  it 'should call the guard with the params passed in' do
    event = AASM::Event.new(:event) do
      transitions :to => :closed, :from => [:open, :received], :guard => :guard_fn
    end

    obj = mock('object')
    obj.stub!(:aasm_current_state).and_return(:open)
    obj.should_receive(:guard_fn).with('arg1', 'arg2').and_return(true)

    event.fire(obj, nil, 'arg1', 'arg2').should == :closed
  end

end

describe 'should fire callbacks' do
  describe 'success' do
    it "if it's a symbol" do
      ThisNameBetterNotBeInUse.instance_eval {
        aasm_event :with_symbol, :success => :symbol_success_callback do
          transitions :to => :symbol, :from => [:initial]
        end
      }

      model = ThisNameBetterNotBeInUse.new
      model.should_receive(:symbol_success_callback)
      model.with_symbol!
    end

    it "if it's a string" do
      ThisNameBetterNotBeInUse.instance_eval {
        aasm_event :with_string, :success => 'string_success_callback' do
          transitions :to => :string, :from => [:initial]
        end
      }

      model = ThisNameBetterNotBeInUse.new
      model.should_receive(:string_success_callback)
      model.with_string!
    end

    it "if passed an array of strings and/or symbols" do
      ThisNameBetterNotBeInUse.instance_eval {
        aasm_event :with_array, :success => [:success_callback1, 'success_callback2'] do
          transitions :to => :array, :from => [:initial]
        end
      }

      model = ThisNameBetterNotBeInUse.new
      model.should_receive(:success_callback1)
      model.should_receive(:success_callback2)
      model.with_array!
    end

    it "if passed an array of strings and/or symbols and/or procs" do
      ThisNameBetterNotBeInUse.instance_eval {
        aasm_event :with_array_including_procs, :success => [:success_callback1, 'success_callback2', lambda { proc_success_callback }] do
          transitions :to => :array, :from => [:initial]
        end
      }

      model = ThisNameBetterNotBeInUse.new
      model.should_receive(:success_callback1)
      model.should_receive(:success_callback2)
      model.should_receive(:proc_success_callback)
      model.with_array_including_procs!
    end

    it "if it's a proc" do
      ThisNameBetterNotBeInUse.instance_eval {
        aasm_event :with_proc, :success => lambda { proc_success_callback } do
          transitions :to => :proc, :from => [:initial]
        end
      }

      model = ThisNameBetterNotBeInUse.new
      model.should_receive(:proc_success_callback)
      model.with_proc!
    end
  end

  describe 'after' do
    it "if they set different ways" do
      ThisNameBetterNotBeInUse.instance_eval do
        aasm_event :with_afters, :after => :do_one_thing_after do
          after do
            do_another_thing_after_too
          end
          after do
            do_third_thing_at_last
          end
          transitions :to => :proc, :from => [:initial]
        end
      end

      model = ThisNameBetterNotBeInUse.new
      model.should_receive(:do_one_thing_after).once.ordered
      model.should_receive(:do_another_thing_after_too).once.ordered
      model.should_receive(:do_third_thing_at_last).once.ordered
      model.with_afters!
    end
  end

  describe 'before' do
    it "if it's a proc" do
      ThisNameBetterNotBeInUse.instance_eval do
        aasm_event :before_as_proc do
          before do
            do_something_before
          end
          transitions :to => :proc, :from => [:initial]
        end
      end

      model = ThisNameBetterNotBeInUse.new
      model.should_receive(:do_something_before).once
      model.before_as_proc!
    end
  end

  it 'in right order' do
    ThisNameBetterNotBeInUse.instance_eval do
      aasm_event :in_right_order, :after => :do_something_after do
        before do
          do_something_before
        end
        transitions :to => :proc, :from => [:initial]
      end
    end

    model = ThisNameBetterNotBeInUse.new
    model.should_receive(:do_something_before).once.ordered
    model.should_receive(:do_something_after).once.ordered
    model.in_right_order!
  end
end

describe 'parametrised events' do
  let(:pe) {ParametrisedEvent.new}

  it 'should transition to specified next state (sleeping to showering)' do
    pe.wakeup!(:showering)
    pe.aasm_current_state.should == :showering
  end

  it 'should transition to specified next state (sleeping to working)' do
    pe.wakeup!(:working)
    pe.aasm_current_state.should == :working
  end

  it 'should transition to default (first or showering) state' do
    pe.wakeup!
    pe.aasm_current_state.should == :showering
  end

  it 'should transition to default state when on_transition invoked' do
    pe.dress!(nil, 'purple', 'dressy')
    pe.aasm_current_state.should == :working
  end

  it 'should call on_transition method with args' do
    pe.wakeup!(:showering)
    pe.should_receive(:wear_clothes).with('blue', 'jeans')
    pe.dress!(:working, 'blue', 'jeans')
  end

  it 'should call on_transition proc' do
    pe.wakeup!(:showering)
    pe.should_receive(:wear_clothes).with('purple', 'slacks')
    pe.dress!(:dating, 'purple', 'slacks')
  end

  it 'should call on_transition with an array of methods' do
    pe.wakeup!(:showering)
    pe.should_receive(:condition_hair)
    pe.should_receive(:fix_hair)
    pe.dress!(:prettying_up)
  end
end

describe 'event firing without persistence' do
  it 'should attempt to persist if aasm_write_state is defined' do
    foo = Foo.new
    def foo.aasm_write_state; end
    foo.should be_open

    foo.should_receive(:aasm_write_state_without_persistence)
    foo.close
  end
end


================================================
FILE: spec/unit/initial_state_spec.rb
================================================
require 'spec_helper'

class Banker
  include AASM
  aasm do
    state :retired
    state :selling_bad_mortgages
  end
  aasm_initial_state  Proc.new { |banker| banker.rich? ? :retired : :selling_bad_mortgages }
  RICH = 1_000_000
  attr_accessor :balance
  def initialize(balance = 0); self.balance = balance; end
  def rich?; self.balance >= RICH; end
end

describe 'initial states' do
  let(:bar) {Bar.new}

  it 'should use the first state defined if no initial state is given' do
    bar.aasm_current_state.should == :read
    # bar.aasm.current_state.should == :read # not yet supported
  end

  it 'should determine initial state from the Proc results' do
    Banker.new(Banker::RICH - 1).aasm_current_state.should == :selling_bad_mortgages
    Banker.new(Banker::RICH + 1).aasm_current_state.should == :retired
  end
end


================================================
FILE: spec/unit/inspection_spec.rb
================================================
require 'spec_helper'

describe 'inspection for common cases' do
  it 'should support the old DSL' do
    Foo.should respond_to(:aasm_states)
    Foo.aasm_states.should include(:open)
    Foo.aasm_states.should include(:closed)

    Foo.should respond_to(:aasm_initial_state)
    Foo.aasm_initial_state.should == :open

    Foo.should respond_to(:aasm_events)
    Foo.aasm_events.should include(:close)
    Foo.aasm_events.should include(:null)
  end

  it 'should support the new DSL' do
    Foo.aasm.should respond_to(:states)
    Foo.aasm.states.should include(:open)
    Foo.aasm.states.should include(:closed)

    Foo.aasm.should respond_to(:initial_state)
    Foo.aasm.initial_state.should == :open

    Foo.aasm.should respond_to(:events)
    Foo.aasm.events.should include(:close)
    Foo.aasm.events.should include(:null)
  end

  context "instance level inspection" do
    let(:foo) { Foo.new }
    let(:two) { FooTwo.new }

    it "delivers all states" do
      states = foo.aasm.states
      states.should include(:open)
      states.should include(:closed)

      states = foo.aasm.states(:permissible => true)
      states.should include(:closed)
      states.should_not include(:open)

      foo.close
      foo.aasm.states(:permissible => true).should be_empty
    end

    it "delivers all states for subclasses" do
      states = two.aasm.states
      states.should include(:open)
      states.should include(:closed)
      states.should include(:foo)

      states = two.aasm.states(:permissible => true)
      states.should include(:closed)
      states.should_not include(:open)

      two.close
      two.aasm.states(:permissible => true).should be_empty
    end

    it "delivers all events" do
      events = foo.aasm.events
      events.should include(:close)
      events.should include(:null)
      foo.close
      foo.aasm.events.should be_empty
    end
  end

  it 'should list states in the order they have been defined' do
    Conversation.aasm.states.should == [:needs_attention, :read, :closed, :awaiting_response, :junk]
  end
end

describe "special cases" do
  it "should support valid a state name" do
    Argument.aasm_states.should include(:invalid)
    Argument.aasm_states.should include(:valid)

    argument = Argument.new
    argument.invalid?.should be_true
    argument.aasm_current_state.should == :invalid

    argument.valid!
    argument.valid?.should be_true
    argument.aasm_current_state.should == :valid
  end
end

describe :aasm_states_for_select do
  it "should return a select friendly array of states" do
    Foo.should respond_to(:aasm_states_for_select)
    Foo.aasm_states_for_select.should == [['Open', 'open'], ['Closed', 'closed']]
  end
end

describe :aasm_from_states_for_state do
  it "should return all from states for a state" do
    AuthMachine.should respond_to(:aasm_from_states_for_state)
    froms = AuthMachine.aasm_from_states_for_state(:active)
    [:pending, :passive, :suspended].each {|from| froms.should include(from)}
  end

  it "should return from states for a state for a particular transition only" do
    froms = AuthMachine.aasm_from_states_for_state(:active, :transition => :unsuspend)
    [:suspended].each {|from| froms.should include(from)}
  end
end

describe 'permissible events' do
  let(:foo) {Foo.new}

  it 'work' do
    foo.aasm.permissible_events.should include(:close)
    foo.aasm.permissible_events.should_not include(:null)
  end
end


================================================
FILE: spec/unit/localizer_spec.rb
================================================
require 'spec_helper'
require 'active_record'
require 'logger'
require 'i18n'

load_schema

class LocalizerTestModel < ActiveRecord::Base
  include AASM

  attr_accessor :aasm_state

  aasm_initial_state :opened
  aasm_state :opened
  aasm_state :closed

  aasm_event :close
  aasm_event :open
end

describe 'localized state names' do
  before(:all) do
    I18n.load_path << 'spec/en.yml'
    I18n.default_locale = :en
    I18n.reload!
  end

  after(:all) do
    I18n.load_path.clear
  end

  it 'should localize' do
    LocalizerTestModel.aasm.states.detect {|s| s == :opened}.localized_name.should == "It's open now!"
  end

  it 'should use fallback' do
    LocalizerTestModel.aasm.states.detect {|s| s == :closed}.localized_name.should == 'Closed'
  end
end

describe AASM::Localizer, "new style" do
  before(:all) do
    I18n.load_path << 'spec/en.yml'
    I18n.default_locale = :en
    I18n.reload!
  end

  after(:all) do
    I18n.load_path.clear
  end

  let (:foo_opened) { LocalizerTestModel.new }
  let (:foo_closed) { LocalizerTestModel.new.tap { |x| x.aasm_state = :closed  } }

  context 'aasm_human_state' do
    it 'should return translated state value' do
      foo_opened.aasm_human_state.should == "It's open now!"
    end

    it 'should return humanized value if not localized' do
      foo_closed.aasm_human_state.should == "Closed"
    end
  end

  context 'aasm_human_event_name' do
    it 'should return translated event name' do
      LocalizerTestModel.aasm_human_event_name(:close).should == "Let's close it!"
    end

    it 'should return humanized event name' do
      LocalizerTestModel.aasm_human_event_name(:open).should == "Open"
    end
  end
end

describe AASM::Localizer, "deprecated style" do
  before(:all) do
    I18n.load_path << 'spec/en_deprecated_style.yml'
    I18n.default_locale = :en
    I18n.reload!
  end

  after(:all) do
    I18n.load_path.clear
  end

  let (:foo_opened) { LocalizerTestModel.new }
  let (:foo_closed) { LocalizerTestModel.new.tap { |x| x.aasm_state = :closed  } }

  context 'aasm_human_state' do
    it 'should return translated state value' do
      foo_opened.aasm_human_state.should == "It's open now!"
    end

    it 'should return humanized value if not localized' do
      foo_closed.aasm_human_state.should == "Closed"
    end
  end

  context 'aasm_human_event_name' do
    it 'should return translated event name' do
      LocalizerTestModel.aasm_human_event_name(:close).should == "Let's close it!"
    end

    it 'should return humanized event name' do
      LocalizerTestModel.aasm_human_event_name(:open).should == "Open"
    end
  end
end


================================================
FILE: spec/unit/memory_leak_spec.rb
================================================
# require 'spec_helper'

# describe "state machines" do

#   def number_of_objects(clazz)
#     ObjectSpace.each_object(clazz) {}
#   end

#   def machines
#     AASM::StateMachine.instance_variable_get("@machines")
#   end

#   it "should be created without memory leak" do
#     machines_count = machines.size
#     state_count = number_of_objects(AASM::State)
#     event_count = number_of_objects(AASM::Event)
#     puts "event_count = #{event_count}"
#     transition_count = number_of_objects(AASM::Transition)

#     load File.expand_path(File.dirname(__FILE__) + '/../models/not_auto_loaded/process.rb')
#     machines.size.should == machines_count + 1                                                  # + Process
#     number_of_objects(Models::Process).should == 0
#     number_of_objects(AASM::State).should == state_count + 3                 # + Process
#     puts "event_count = #{number_of_objects(AASM::Event)}"
#     number_of_objects(AASM::Event).should == event_count + 2                 # + Process
#     number_of_objects(AASM::Transition).should == transition_count + 2  # + Process

#     Models.send(:remove_const, "Process") if Models.const_defined?("Process")
#     load File.expand_path(File.dirname(__FILE__) + '/../models/not_auto_loaded/process.rb')
#     machines.size.should == machines_count + 1                                                  # + Process
#     number_of_objects(AASM::State).should == state_count + 3                 # + Process
#     # ObjectSpace.each_object(AASM::Event) {|o| puts o.inspect}
#     puts "event_count = #{number_of_objects(AASM::Event)}"
#     number_of_objects(AASM::Event).should == event_count + 2                 # + Process
#     number_of_objects(AASM::Transition).should == transition_count + 2  # + Process
#   end

# end


================================================
FILE: spec/unit/new_dsl_spec.rb
================================================
require 'spec_helper'

describe "the new dsl" do

  let(:process) {ProcessWithNewDsl.new}

  it 'should not conflict with other event or state methods' do
    lambda {ProcessWithNewDsl.state}.should raise_error(RuntimeError, "wrong state method")
    lambda {ProcessWithNewDsl.event}.should raise_error(RuntimeError, "wrong event method")
  end

end


================================================
FILE: spec/unit/persistence/active_record_persistence_spec.rb
================================================
require 'active_record'
require 'logger'
require 'spec_helper'

load_schema

# if you want to see the statements while running the spec enable the following line
# ActiveRecord::Base.logger = Logger.new(STDERR)

shared_examples_for "aasm model" do
  it "should include persistence mixins" do
    klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence)
    klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::InstanceMethods)
  end
end

describe "instance methods" do
  let(:gate) {Gate.new}

  it "should respond to aasm persistence methods" do
    gate.should respond_to(:aasm_read_state)
    gate.should respond_to(:aasm_write_state)
    gate.should respond_to(:aasm_write_state_without_persistence)
  end

  it "should return the initial state when new and the aasm field is nil" do
    gate.aasm_current_state.should == :opened
  end

  it "should return the aasm column when new and the aasm field is not nil" do
    gate.aasm_state = "closed"
    gate.aasm_current_state.should == :closed
  end

  it "should return the aasm column when not new and the aasm_column is not nil" do
    gate.stub!(:new_record?).and_return(false)
    gate.aasm_state = "state"
    gate.aasm_current_state.should == :state
  end

  it "should allow a nil state" do
    gate.stub!(:new_record?).and_return(false)
    gate.aasm_state = nil
    gate.aasm_current_state.should be_nil
  end

  it "should call aasm_ensure_initial_state on validation before create" do
    gate.should_receive(:aasm_ensure_initial_state).and_return(true)
    gate.valid?
  end

  it "should not call aasm_ensure_initial_state on validation before update" do
    gate.stub!(:new_record?).and_return(false)
    gate.should_not_receive(:aasm_ensure_initial_state)
    gate.valid?
  end

end

describe 'subclasses' do
  it "should have the same states as its parent class" do
    Derivate.aasm_states.should == Simple.aasm_states
  end

  it "should have the same events as its parent class" do
    Derivate.aasm_events.should == Simple.aasm_events
  end

  it "should have the same column as its parent class" do
    Derivate.aasm_column.should == :status
  end

  it "should have the same column as its parent even for the new dsl" do
    SimpleNewDsl.aasm_column.should == :status
    DerivateNewDsl.aasm_column.should == :status
  end
end

describe "named scopes with the old DSL" do

  context "Does not already respond_to? the scope name" do
    it "should add a scope" do
      Simple.should respond_to(:unknown_scope)
      SimpleNewDsl.unknown_scope.is_a?(ActiveRecord::Relation).should be_true
    end
  end

  context "Already respond_to? the scope name" do
    it "should not add a scope" do
      Simple.should respond_to(:new)
      Simple.new.class.should == Simple
    end
  end

end

describe "named scopes with the new DSL" do

  context "Does not already respond_to? the scope name" do
    it "should add a scope" do
      SimpleNewDsl.should respond_to(:unknown_scope)
      SimpleNewDsl.unknown_scope.is_a?(ActiveRecord::Relation).should be_true
    end
  end

  context "Already respond_to? the scope name" do
    it "should not add a scope" do
      SimpleNewDsl.should respond_to(:new)
      SimpleNewDsl.new.class.should == SimpleNewDsl
    end
  end

end

describe 'initial states' do

  it 'should support conditions' do
    Thief.new(:skilled => true).aasm_current_state.should == :rich
    Thief.new(:skilled => false).aasm_current_state.should == :jailed
  end
end

describe 'transitions with persistence' do

  it "should work for valid models" do
    valid_object = Validator.create(:name => 'name')
    valid_object.should be_sleeping
    valid_object.status = :running
    valid_object.should be_running
  end

  it 'should not store states for invalid models' do
    validator = Validator.create(:name => 'name')
    validator.should be_valid
    validator.should be_sleeping

    validator.name = nil
    validator.should_not be_valid
    validator.run!.should be_false
    validator.should be_sleeping

    validator.reload
    validator.should_not be_running
    validator.should be_sleeping

    validator.name = 'another name'
    validator.should be_valid
    validator.run!.should be_true
    validator.should be_running

    validator.reload
    validator.should be_running
    validator.should_not be_sleeping
  end

  it 'should store states for invalid models if configured' do
    persistor = InvalidPersistor.create(:name => 'name')
    persistor.should be_valid
    persistor.should be_sleeping

    persistor.name = nil
    persistor.should_not be_valid
    persistor.run!.should be_true
    persistor.should be_running

    persistor = InvalidPersistor.find(persistor.id)
    persistor.valid?
    persistor.should be_valid
    persistor.should be_running
    persistor.should_not be_sleeping

    persistor.reload
    persistor.should be_running
    persistor.should_not be_sleeping
  end

  describe 'transactions' do
    it 'should rollback all changes' do
      worker = Worker.create!(:name => 'worker', :status => 'sleeping')
      transactor = Transactor.create!(:name => 'transactor', :worker => worker)
      transactor.should be_sleeping
      worker.status.should == 'sleeping'

      lambda {transactor.run!}.should raise_error(StandardError, 'failed on purpose')
      transactor.should be_running
      worker.reload.status.should == 'sleeping'
    end
  end

end


================================================
FILE: spec/unit/persistence/mongoid_persistance_spec.rb
================================================
describe 'mongoid', :if => Gem::Version.create(RUBY_VERSION.dup) >= Gem::Version.create('1.9.3') do
# describe 'mongoid' do

  before(:all) do
    require 'mongoid'
    require 'logger'
    require 'spec_helper'
    Dir[File.dirname(__FILE__) + "/../../models/mongoid/*.rb"].sort.each { |f| require File.expand_path(f) }

    # if you want to see the statements while running the spec enable the following line
    # Mongoid.logger = Logger.new(STDERR)

    DATABASE_NAME = "mongoid_#{Process.pid}"

    Mongoid.configure do |config|
      config.connect_to DATABASE_NAME
    end
  end

  after do
    Mongoid.purge!
  end

  describe "named scopes with the old DSL" do

    context "Does not already respond_to? the scope name" do
      it "should add a scope" do
        SimpleMongoid.should respond_to(:unknown_scope)
        SimpleMongoid.unknown_scope.class.should == Mongoid::Criteria
      end
    end

    context "Already respond_to? the scope name" do
      it "should not add a scope" do
        SimpleMongoid.should respond_to(:new)
        SimpleMongoid.new.class.should == SimpleMongoid
      end
    end

  end

  describe "named scopes with the new DSL" do

    context "Does not already respond_to? the scope name" do
      it "should add a scope" do
        SimpleNewDslMongoid.should respond_to(:unknown_scope)
        SimpleNewDslMongoid.unknown_scope.class.should == Mongoid::Criteria
      end
    end

    context "Already respond_to? the scope name" do
      it "should not add a scope" do
        SimpleNewDslMongoid.should respond_to(:new)
        SimpleNewDslMongoid.new.class.should == SimpleNewDslMongoid
      end
    end

  end

  describe "#find_in_state" do

    let!(:model)    { SimpleNewDslMongoid.create!(:status => :unknown_scope) }
    let!(:model_id) { model._id }

    it "should respond to method" do
      SimpleNewDslMongoid.should respond_to(:find_in_state)
    end

    it "should find the model when given the correct scope and model id" do
      SimpleNewDslMongoid.find_in_state(model_id, 'unknown_scope').class.should == SimpleNewDslMongoid
      SimpleNewDslMongoid.find_in_state(model_id, 'unknown_scope').should == model
    end

    it "should raise DocumentNotFound error when given incorrect scope" do
      expect {SimpleNewDslMongoid.find_in_state(model_id, 'new')}.to raise_error Mongoid::Errors::DocumentNotFound
    end

    it "should raise DocumentNotFound error when given incorrect model id" do
      expect {SimpleNewDslMongoid.find_in_state('bad_id', 'unknown_scope')}.to raise_error Mongoid::Errors::DocumentNotFound
    end

  end

  describe "#count_in_state" do

    before do
      3.times { SimpleNewDslMongoid.create!(:status => :unknown_scope) }
    end

    it "should respond to method" do
      SimpleNewDslMongoid.should respond_to(:count_in_state)
    end

    it "should return n for a scope with n records persisted" do
      SimpleNewDslMongoid.count_in_state('unknown_scope').class.should == Fixnum
      SimpleNewDslMongoid.count_in_state('unknown_scope').should == 3
    end

    it "should return zero for a scope without records persisted" do
      SimpleNewDslMongoid.count_in_state('new').class.should == Fixnum
      SimpleNewDslMongoid.count_in_state('new').should == 0
    end

  end

  describe "#with_state_scope" do

    before do
      3.times { SimpleNewDslMongoid.create!(:status => :unknown_scope) }
      2.times { SimpleNewDslMongoid.create!(:status => :new) }
    end

    it "should respond to method" do
      SimpleNewDslMongoid.should respond_to(:with_state_scope)
    end

    it "should correctly process block" do
      SimpleNewDslMongoid.with_state_scope('unknown_scope') do
        SimpleNewDslMongoid.count
      end.should == 3
      SimpleNewDslMongoid.with_state_scope('new') do
        SimpleNewDslMongoid.count
      end.should == 2
    end

  end
end


================================================
FILE: spec/unit/simple_example_spec.rb
================================================
require 'spec_helper'

class Payment
  include AASM
  aasm do
    state :initialised, :initial => true
    state :filled_out
    state :authorised

    event :fill_out do
      transitions :from => :initialised, :to => :filled_out
    end
    event :authorise do
      transitions :from => :filled_out, :to => :authorised
    end
  end
end

describe 'state machine' do
  let(:payment) {Payment.new}

  it 'starts with an initial state' do
    payment.aasm_current_state.should == :initialised
    # payment.aasm.current_state.should == :initialised # not yet supported
    payment.should respond_to(:initialised?)
    payment.should be_initialised
  end

  it 'allows transitions to other states' do
    payment.should respond_to(:fill_out)
    payment.should respond_to(:fill_out!)
    payment.fill_out!
    payment.should respond_to(:filled_out?)
    payment.should be_filled_out

    payment.should respond_to(:authorise)
    payment.should respond_to(:authorise!)
    payment.authorise
    payment.should respond_to(:authorised?)
    payment.should be_authorised
  end

  it 'denies transitions to other states' do
    lambda {payment.authorise}.should raise_error(AASM::InvalidTransition)
    lambda {payment.authorise!}.should raise_error(AASM::InvalidTransition)
    payment.fill_out
    lambda {payment.fill_out}.should raise_error(AASM::InvalidTransition)
    lambda {payment.fill_out!}.should raise_error(AASM::InvalidTransition)
    payment.authorise
    lambda {payment.fill_out}.should raise_error(AASM::InvalidTransition)
    lambda {payment.fill_out!}.should raise_error(AASM::InvalidTransition)
  end

  it 'defines constants for each state name' do
    Payment::STATE_INITIALISED.should eq(:initialised)
    Payment::STATE_FILLED_OUT.should eq(:filled_out)
    Payment::STATE_AUTHORISED.should eq(:authorised)
  end
end


================================================
FILE: spec/unit/state_spec.rb
================================================
require 'spec_helper'

describe AASM::State do
  before(:each) do
    @name    = :astate
    @options = { :crazy_custom_key => 'key' }
  end

  def new_state(options={})
    AASM::State.new(@name, Conversation, @options.merge(options))
  end

  it 'should set the name' do
    state = new_state
    state.name.should == :astate
  end

  it 'should set the display_name from name' do
    new_state.display_name.should == 'Astate'
  end

  it 'should set the display_name from options' do
    new_state(:display => "A State").display_name.should == 'A State'
  end

  it 'should set the options and expose them as options' do
    new_state.options.should == @options
  end

  it 'should be equal to a symbol of the same name' do
    new_state.should == :astate
  end

  it 'should be equal to a State of the same name' do
    new_state.should == new_state
  end

  it 'should send a message to the record for an action if the action is present as a symbol' do
    state = new_state(:entering => :foo)

    record = mock('record')
    record.should_receive(:foo)

    state.fire_callbacks(:entering, record)
  end

  it 'should send a message to the record for an action if the action is present as a string' do
    state = new_state(:entering => 'foo')

    record = mock('record')
    record.should_receive(:foo)

    state.fire_callbacks(:entering, record)
  end

  it 'should send a message to the record for each action' do
    state = new_state(:entering => [:a, :b, "c", lambda {|r| r.foobar }])

    record = mock('record')
    record.should_receive(:a)
    record.should_receive(:b)
    record.should_receive(:c)
    record.should_receive(:foobar)

    state.fire_callbacks(:entering, record)
  end

  it "should stop calling actions if one of them raises :halt_aasm_chain" do
    state = new_state(:entering => [:a, :b, :c])

    record = mock('record')
    record.should_receive(:a)
    record.should_receive(:b).and_throw(:halt_aasm_chain)
    record.should_not_receive(:c)

    state.fire_callbacks(:entering, record)
  end

  it 'should call a proc, passing in the record for an action if the action is present' do
    state = new_state(:entering => Proc.new {|r| r.foobar})

    record = mock('record')
    record.should_receive(:foobar)

    state.fire_callbacks(:entering, record)
  end
end


================================================
FILE: spec/unit/subclassing_spec.rb
================================================
require 'spec_helper'

describe 'subclassing' do
  let(:son) {Son.new}

  it 'should have the parent states' do
    Foo.aasm_states.each do |state|
      FooTwo.aasm_states.should include(state)
    end
    Baz.aasm_states.should == Bar.aasm_states
  end

  it 'should not add the child states to the parent machine' do
    Foo.aasm_states.should_not include(:foo)
  end

  it "should have the same events as its parent" do
    Baz.aasm_events.should == Bar.aasm_events
  end

  it 'should know how to respond to `may_add_details?`' do
    son.may_add_details?.should be_true
  end

  it 'should not break if I call Son#update_state' do
    son.update_state
    son.aasm_current_state.should == :pending_details_confirmation
  end
  
end



================================================
FILE: spec/unit/transition_spec.rb
================================================
require 'spec_helper'

describe 'transitions' do

  it 'should raise an exception when whiny' do
    process = ProcessWithNewDsl.new
    lambda { process.stop! }.should raise_error(AASM::InvalidTransition)
    process.should be_sleeping
  end

  it 'should not raise an exception when not whiny' do
    silencer = Silencer.new
    silencer.smile!.should be_false
    silencer.should be_silent
  end

  it 'should not raise an exception when superclass not whiny' do
    sub = SubClassing.new
    sub.smile!.should be_false
    sub.should be_silent
  end

  it 'should not raise an exception when from is nil even if whiny' do
    silencer = Silencer.new
    silencer.smile_any!.should be_true
    silencer.should be_smiling
  end

end

describe AASM::Transition do
  it 'should set from, to, and opts attr readers' do
    opts = {:from => 'foo', :to => 'bar', :guard => 'g'}
    st = AASM::Transition.new(opts)

    st.from.should == opts[:from]
    st.to.should == opts[:to]
    st.opts.should == opts
  end

  it 'should pass equality check if from and to are the same' do
    opts = {:from => 'foo', :to => 'bar', :guard => 'g'}
    st = AASM::Transition.new(opts)

    obj = mock('object')
    obj.stub!(:from).and_return(opts[:from])
    obj.stub!(:to).and_return(opts[:to])

    st.should == obj
  end

  it 'should fail equality check if from are not the same' do
    opts = {:from => 'foo', :to => 'bar', :guard => 'g'}
    st = AASM::Transition.new(opts)

    obj = mock('object')
    obj.stub!(:from).and_return('blah')
    obj.stub!(:to).and_return(opts[:to])

    st.should_not == obj
  end

  it 'should fail equality check if to are not the same' do
    opts = {:from => 'foo', :to => 'bar', :guard => 'g'}
    st = AASM::Transition.new(opts)

    obj = mock('object')
    obj.stub!(:from).and_return(opts[:from])
    obj.stub!(:to).and_return('blah')

    st.should_not == obj
  end
end

describe AASM::Transition, '- when performing guard checks' do
  it 'should return true of there is no guard' do
    opts = {:from => 'foo', :to => 'bar'}
    st = AASM::Transition.new(opts)

    st.perform(nil).should be_true
  end

  it 'should call the method on the object if guard is a symbol' do
    opts = {:from => 'foo', :to => 'bar', :guard => :test}
    st = AASM::Transition.new(opts)

    obj = mock('object')
    obj.should_receive(:test)

    st.perform(obj)
  end

  it 'should call the method on the object if guard is a string' do
    opts = {:from => 'foo', :to => 'bar', :guard => 'test'}
    st = AASM::Transition.new(opts)

    obj = mock('object')
    obj.should_receive(:test)

    st.perform(obj)
  end

  it 'should call the proc passing the object if the guard is a proc' do
    opts = {:from => 'foo', :to => 'bar', :guard => Proc.new {|o| o.test}}
    st = AASM::Transition.new(opts)

    obj = mock('object')
    obj.should_receive(:test)

    st.perform(obj)
  end
end

describe AASM::Transition, '- when executing the transition with a Proc' do
  it 'should call a Proc on the object with args' do
    opts = {:from => 'foo', :to => 'bar', :on_transition => Proc.new {|o| o.test}}
    st = AASM::Transition.new(opts)
    args = {:arg1 => '1', :arg2 => '2'}
    obj = mock('object')

    opts[:on_transition].should_receive(:call).with(any_args)

    st.execute(obj, args)
  end

  it 'should call a Proc on the object without args' do
    opts = {:from => 'foo', :to => 'bar', :on_transition => Proc.new {||}}
    st = AASM::Transition.new(opts)
    args = {:arg1 => '1', :arg2 => '2'}
    obj = mock('object')

    opts[:on_transition].should_receive(:call).with(no_args)

    st.execute(obj, args)
  end
end

describe AASM::Transition, '- when executing the transition with an :on_transtion method call' do
  it 'should accept a String for the method name' do
    opts = {:from => 'foo', :to => 'bar', :on_transition => 'test'}
    st = AASM::Transition.new(opts)
    args = {:arg1 => '1', :arg2 => '2'}
    obj = mock('object')

    obj.should_receive(:test)

    st.execute(obj, args)
  end

  it 'should accept a Symbol for the method name' do
    opts = {:from => 'foo', :to => 'bar', :on_transition => :test}
    st = AASM::Transition.new(opts)
    args = {:arg1 => '1', :arg2 => '2'}
    obj = mock('object')

    obj.should_receive(:test)

    st.execute(obj, args)
  end

  it 'should pass args if the target method accepts them' do
    opts = {:from => 'foo', :to => 'bar', :on_transition => :test}
    st = AASM::Transition.new(opts)
    args = {:arg1 => '1', :arg2 => '2'}
    obj = mock('object')

    obj.class.class_eval do
      define_method(:test) {|*args| 'success'}
    end

    return_value = st.execute(obj, args)

    return_value.should == 'success'
  end

  it 'should NOT pass args if the target method does NOT accept them' do
    opts = {:from => 'foo', :to => 'bar', :on_transition => :test}
    st = AASM::Transition.new(opts)
    args = {:arg1 => '1', :arg2 => '2'}
    obj = mock('object')

    obj.class.class_eval do
      define_method(:test) {|*args| 'success'}
    end

    return_value = st.execute(obj, args)

    return_value.should == 'success'
  end

end
Download .txt
gitextract_cxl63xfk/

├── .document
├── .gitignore
├── .travis.yml
├── API
├── CHANGELOG.md
├── Gemfile
├── HOWTO
├── LICENSE
├── README.md
├── Rakefile
├── aasm.gemspec
├── lib/
│   ├── aasm/
│   │   ├── aasm.rb
│   │   ├── base.rb
│   │   ├── deprecated/
│   │   │   └── aasm.rb
│   │   ├── errors.rb
│   │   ├── event.rb
│   │   ├── instance_base.rb
│   │   ├── localizer.rb
│   │   ├── persistence/
│   │   │   ├── active_record_persistence.rb
│   │   │   ├── base.rb
│   │   │   └── mongoid_persistence.rb
│   │   ├── persistence.rb
│   │   ├── state.rb
│   │   ├── state_machine.rb
│   │   ├── transition.rb
│   │   └── version.rb
│   └── aasm.rb
└── spec/
    ├── database.yml
    ├── en.yml
    ├── en_deprecated_style.yml
    ├── models/
    │   ├── active_record/
    │   │   └── api.rb
    │   ├── argument.rb
    │   ├── auth_machine.rb
    │   ├── bar.rb
    │   ├── callback_new_dsl.rb
    │   ├── callback_old_dsl.rb
    │   ├── conversation.rb
    │   ├── father.rb
    │   ├── foo.rb
    │   ├── invalid_persistor.rb
    │   ├── mongoid/
    │   │   ├── simple_mongoid.rb
    │   │   └── simple_new_dsl_mongoid.rb
    │   ├── not_auto_loaded/
    │   │   └── process.rb
    │   ├── parametrised_event.rb
    │   ├── persistence.rb
    │   ├── process_with_new_dsl.rb
    │   ├── silencer.rb
    │   ├── son.rb
    │   ├── sub_classing.rb
    │   ├── this_name_better_not_be_in_use.rb
    │   ├── transactor.rb
    │   ├── validator.rb
    │   └── worker.rb
    ├── schema.rb
    ├── spec_helper.rb
    └── unit/
        ├── api_spec.rb
        ├── callbacks_spec.rb
        ├── complex_example_spec.rb
        ├── event_spec.rb
        ├── initial_state_spec.rb
        ├── inspection_spec.rb
        ├── localizer_spec.rb
        ├── memory_leak_spec.rb
        ├── new_dsl_spec.rb
        ├── persistence/
        │   ├── active_record_persistence_spec.rb
        │   └── mongoid_persistance_spec.rb
        ├── simple_example_spec.rb
        ├── state_spec.rb
        ├── subclassing_spec.rb
        └── transition_spec.rb
Download .txt
SYMBOL INDEX (258 symbols across 45 files)

FILE: lib/aasm/aasm.rb
  type AASM (line 1) | module AASM
    function included (line 3) | def self.included(base) #:nodoc:
    type ClassMethods (line 14) | module ClassMethods
      function inherited (line 17) | def inherited(base)
      function aasm (line 23) | def aasm(options={}, &block)
      function aasm_initial_state (line 30) | def aasm_initial_state(set_state=nil)
      function aasm_from_states_for_state (line 40) | def aasm_from_states_for_state(state, options={})
      function aasm_initial_state= (line 49) | def aasm_initial_state=(state)
      function aasm_state (line 54) | def aasm_state(name, options={})
      function aasm_event (line 59) | def aasm_event(name, options = {}, &block)
      function aasm_states (line 64) | def aasm_states
      function aasm_events (line 69) | def aasm_events
      function aasm_states_for_select (line 74) | def aasm_states_for_select
      function aasm_human_event_name (line 79) | def aasm_human_event_name(event) # event_name?
    function aasm (line 84) | def aasm
    function aasm_read_state (line 89) | def aasm_read_state
    function aasm_write_state (line 97) | def aasm_write_state(new_state)
    function aasm_write_state_without_persistence (line 102) | def aasm_write_state_without_persistence(new_state)
    function aasm_current_state (line 107) | def aasm_current_state
    function aasm_enter_initial_state (line 113) | def aasm_enter_initial_state
    function aasm_events_for_current_state (line 119) | def aasm_events_for_current_state
    function aasm_permissible_events_for_current_state (line 125) | def aasm_permissible_events_for_current_state
    function aasm_events_for_state (line 131) | def aasm_events_for_state(state_name)
    function aasm_human_state (line 137) | def aasm_human_state
    function aasm_fire_event (line 144) | def aasm_fire_event(event_name, options, *args)
    function fired (line 163) | def fired(event, old_state, new_state_name, options)
    function failed (line 195) | def failed(event_name, old_state)

FILE: lib/aasm/base.rb
  type AASM (line 1) | module AASM
    class Base (line 2) | class Base
      method initialize (line 4) | def initialize(clazz, options={}, &block)
      method initial_state (line 22) | def initial_state
      method state (line 27) | def state(name, options={})
      method event (line 42) | def event(name, options={}, &block)
      method states (line 65) | def states
      method events (line 69) | def events
      method states_for_select (line 73) | def states_for_select

FILE: lib/aasm/deprecated/aasm.rb
  type AASM (line 1) | module AASM
    type ClassMethods (line 3) | module ClassMethods
      function human_event_name (line 4) | def human_event_name(*args)
    function human_state (line 10) | def human_state

FILE: lib/aasm/errors.rb
  type AASM (line 1) | module AASM
    class InvalidTransition (line 2) | class InvalidTransition < RuntimeError; end
    class UndefinedState (line 3) | class UndefinedState < RuntimeError; end

FILE: lib/aasm/event.rb
  type AASM (line 1) | module AASM
    class Event (line 2) | class Event
      method initialize (line 6) | def initialize(name, options = {}, &block)
      method may_fire? (line 15) | def may_fire?(obj, to_state=nil, *args)
      method fire (line 19) | def fire(obj, to_state=nil, *args)
      method transitions_from_state? (line 23) | def transitions_from_state?(state)
      method transitions_from_state (line 27) | def transitions_from_state(state)
      method transitions_to_state? (line 31) | def transitions_to_state?(state)
      method transitions_to_state (line 35) | def transitions_to_state(state)
      method all_transitions (line 40) | def all_transitions
      method fire_callbacks (line 45) | def fire_callbacks(callback_name, record, *args)
      method == (line 49) | def ==(event)
      method update (line 59) | def update(options = {}, &block)
      method _fire (line 68) | def _fire(obj, test, to_state=nil, *args)
      method invoke_callbacks (line 93) | def invoke_callbacks(code, record, args)
      method transitions (line 110) | def transitions(trans_opts=nil)

FILE: lib/aasm/instance_base.rb
  type AASM (line 1) | module AASM
    class InstanceBase (line 2) | class InstanceBase
      method initialize (line 4) | def initialize(instance)
      method current_state (line 8) | def current_state
      method current_state= (line 12) | def current_state=(state)
      method enter_initial_state (line 17) | def enter_initial_state
      method human_state (line 29) | def human_state
      method states (line 33) | def states(options={})
      method events (line 46) | def events(state=current_state)
      method permissible_events (line 54) | def permissible_events
      method state_object_for_name (line 58) | def state_object_for_name(name)
      method determine_state_name (line 64) | def determine_state_name(state)
      method may_fire_event? (line 75) | def may_fire_event?(name, *args)
      method set_current_state_with_persistence (line 80) | def set_current_state_with_persistence(state)

FILE: lib/aasm/localizer.rb
  type AASM (line 1) | module AASM
    class Localizer (line 2) | class Localizer
      method human_event_name (line 3) | def human_event_name(klass, event)
      method human_state_name (line 11) | def human_state_name(klass, state)
      method item_for (line 22) | def item_for(klass, state, ancestor, options={})
      method translate_queue (line 27) | def translate_queue(checklist)
      method i18n_scope (line 39) | def i18n_scope(klass)
      method i18n_klass (line 44) | def i18n_klass(klass)
      method ancestors_list (line 48) | def ancestors_list(klass)

FILE: lib/aasm/persistence.rb
  type AASM (line 1) | module AASM
    type Persistence (line 2) | module Persistence
      function load_persistence (line 5) | def load_persistence(base)
      function require_files_for (line 20) | def require_files_for(persistence)

FILE: lib/aasm/persistence/active_record_persistence.rb
  type AASM (line 1) | module AASM
    type Persistence (line 2) | module Persistence
      type ActiveRecordPersistence (line 3) | module ActiveRecordPersistence
        function included (line 29) | def self.included(base)
        type ClassMethods (line 41) | module ClassMethods
          function find_in_state (line 43) | def find_in_state(number, state, *args)
          function count_in_state (line 49) | def count_in_state(state, *args)
          function calculate_in_state (line 55) | def calculate_in_state(state, *args)
          function with_state_scope (line 62) | def with_state_scope(state)
        type InstanceMethods (line 69) | module InstanceMethods
          function aasm_write_state (line 80) | def aasm_write_state(state)
          function aasm_write_state_without_persistence (line 109) | def aasm_write_state_without_persistence(state)
          function aasm_ensure_initial_state (line 130) | def aasm_ensure_initial_state
          function aasm_fire_event (line 134) | def aasm_fire_event(name, options, *args)

FILE: lib/aasm/persistence/base.rb
  type AASM (line 1) | module AASM
    type Persistence (line 2) | module Persistence
      type Base (line 3) | module Base
        function included (line 5) | def self.included(base) #:nodoc:
        function aasm_read_state (line 35) | def aasm_read_state
        type ClassMethods (line 44) | module ClassMethods
          function aasm_column (line 70) | def aasm_column(column_name=nil)
    class Base (line 86) | class Base
      method state_with_scope (line 88) | def state_with_scope(name, *args)

FILE: lib/aasm/persistence/mongoid_persistence.rb
  type AASM (line 1) | module AASM
    type Persistence (line 2) | module Persistence
      type MongoidPersistence (line 3) | module MongoidPersistence
        function included (line 31) | def self.included(base)
        type ClassMethods (line 41) | module ClassMethods
          function find_in_state (line 43) | def find_in_state(number, state, *args)
          function count_in_state (line 49) | def count_in_state(state, *args)
          function with_state_scope (line 55) | def with_state_scope(state)
        type InstanceMethods (line 63) | module InstanceMethods
          function aasm_write_state (line 75) | def aasm_write_state(state)
          function aasm_write_state_without_persistence (line 99) | def aasm_write_state_without_persistence(state)
          function aasm_ensure_initial_state (line 120) | def aasm_ensure_initial_state
        type NamedScopeMethods (line 125) | module NamedScopeMethods
          function aasm_state_with_named_scope (line 126) | def aasm_state_with_named_scope name, options = {}

FILE: lib/aasm/state.rb
  type AASM (line 1) | module AASM
    class State (line 2) | class State
      method initialize (line 5) | def initialize(name, clazz, options={})
      method == (line 11) | def ==(state)
      method <=> (line 19) | def <=>(state)
      method to_s (line 27) | def to_s
      method fire_callbacks (line 31) | def fire_callbacks(action, record)
      method display_name (line 40) | def display_name
      method localized_name (line 50) | def localized_name
      method for_select (line 54) | def for_select
      method update (line 60) | def update(options = {})
      method _fire_callbacks (line 68) | def _fire_callbacks(action, record)

FILE: lib/aasm/state_machine.rb
  type AASM (line 1) | module AASM
    class StateMachine (line 2) | class StateMachine
      method [] (line 5) | def self.[](clazz)
      method []= (line 9) | def self.[]=(clazz, machine)
      method initialize (line 17) | def initialize(name)
      method initialize_copy (line 26) | def initialize_copy(orig)
      method add_state (line 32) | def add_state(name, clazz, options)

FILE: lib/aasm/transition.rb
  type AASM (line 1) | module AASM
    class Transition (line 2) | class Transition
      method initialize (line 6) | def initialize(opts)
      method perform (line 12) | def perform(obj, *args)
      method execute (line 23) | def execute(obj, *args)
      method == (line 29) | def ==(obj)
      method from? (line 33) | def from?(value)
      method _execute (line 39) | def _execute(obj, on_transition, *args)

FILE: lib/aasm/version.rb
  type AASM (line 1) | module AASM

FILE: spec/models/active_record/api.rb
  class DefaultState (line 1) | class DefaultState
  class ProvidedState (line 14) | class ProvidedState
    method aasm_read_state (line 26) | def aasm_read_state
    method aasm_write_state (line 30) | def aasm_write_state(new_state)
    method aasm_write_state_without_persistence (line 34) | def aasm_write_state_without_persistence(new_state)
  class PersistedState (line 39) | class PersistedState < ActiveRecord::Base
  class ProvidedAndPersistedState (line 52) | class ProvidedAndPersistedState < ActiveRecord::Base
    method aasm_read_state (line 64) | def aasm_read_state
    method aasm_write_state (line 68) | def aasm_write_state(new_state)
    method aasm_write_state_without_persistence (line 72) | def aasm_write_state_without_persistence(new_state)

FILE: spec/models/argument.rb
  class Argument (line 1) | class Argument

FILE: spec/models/auth_machine.rb
  class AuthMachine (line 1) | class AuthMachine
    method initialize (line 46) | def initialize
    method make_activation_code (line 52) | def make_activation_code
    method do_activate (line 56) | def do_activate
    method do_delete (line 61) | def do_delete
    method do_undelete (line 65) | def do_undelete
    method can_register? (line 69) | def can_register?
    method has_activated? (line 73) | def has_activated?
    method has_activation_code? (line 77) | def has_activation_code?
    method if_polite? (line 81) | def if_polite?(phrase = nil)

FILE: spec/models/bar.rb
  class Bar (line 1) | class Bar
  class Baz (line 14) | class Baz < Bar

FILE: spec/models/callback_new_dsl.rb
  class CallbackNewDsl (line 1) | class CallbackNewDsl
    method before_enter_open (line 28) | def before_enter_open; end
    method before_exit_open (line 29) | def before_exit_open; end
    method after_enter_open (line 30) | def after_enter_open; end
    method after_exit_open (line 31) | def after_exit_open; end
    method before_enter_closed (line 33) | def before_enter_closed; end
    method before_exit_closed (line 34) | def before_exit_closed; end
    method after_enter_closed (line 35) | def after_enter_closed; end
    method after_exit_closed (line 36) | def after_exit_closed; end
    method before (line 38) | def before; end
    method after (line 39) | def after; end
    method enter_closed (line 41) | def enter_closed; end
    method exit_open (line 42) | def exit_open; end

FILE: spec/models/callback_old_dsl.rb
  class CallbackOldDsl (line 1) | class CallbackOldDsl
    method before_enter_open (line 26) | def before_enter_open; end
    method before_exit_open (line 27) | def before_exit_open; end
    method after_enter_open (line 28) | def after_enter_open; end
    method after_exit_open (line 29) | def after_exit_open; end
    method before_enter_closed (line 31) | def before_enter_closed; end
    method before_exit_closed (line 32) | def before_exit_closed; end
    method after_enter_closed (line 33) | def after_enter_closed; end
    method after_exit_closed (line 34) | def after_exit_closed; end
    method before (line 36) | def before; end
    method after (line 37) | def after; end
    method enter_closed (line 39) | def enter_closed; end
    method exit_open (line 40) | def exit_open; end

FILE: spec/models/conversation.rb
  class Conversation (line 1) | class Conversation
    method initialize (line 33) | def initialize(persister)
    method aasm_read_state (line 39) | def aasm_read_state
    method aasm_write_state (line 43) | def aasm_write_state(state)

FILE: spec/models/father.rb
  class Father (line 3) | class Father < ActiveRecord::Base
    method update_state (line 15) | def update_state

FILE: spec/models/foo.rb
  class Foo (line 1) | class Foo
    method always_false (line 16) | def always_false
    method success_callback (line 20) | def success_callback
    method enter (line 23) | def enter
    method exit (line 25) | def exit
  class FooTwo (line 29) | class FooTwo < Foo

FILE: spec/models/invalid_persistor.rb
  class InvalidPersistor (line 3) | class InvalidPersistor < ActiveRecord::Base

FILE: spec/models/mongoid/simple_mongoid.rb
  class SimpleMongoid (line 1) | class SimpleMongoid

FILE: spec/models/mongoid/simple_new_dsl_mongoid.rb
  class SimpleNewDslMongoid (line 1) | class SimpleNewDslMongoid

FILE: spec/models/not_auto_loaded/process.rb
  type Models (line 1) | module Models
    class Process (line 2) | class Process

FILE: spec/models/parametrised_event.rb
  class ParametrisedEvent (line 1) | class ParametrisedEvent
    method wear_clothes (line 21) | def wear_clothes(shirt_color, trouser_type)
    method condition_hair (line 24) | def condition_hair
    method fix_hair (line 27) | def fix_hair

FILE: spec/models/persistence.rb
  class Gate (line 1) | class Gate < ActiveRecord::Base
  class Reader (line 17) | class Reader < ActiveRecord::Base
    method aasm_read_state (line 20) | def aasm_read_state
  class Writer (line 25) | class Writer < ActiveRecord::Base
    method aasm_write_state (line 26) | def aasm_write_state(state)
  class Transient (line 32) | class Transient < ActiveRecord::Base
    method aasm_write_state_without_persistence (line 33) | def aasm_write_state_without_persistence(state)
  class Simple (line 39) | class Simple < ActiveRecord::Base
  class SimpleNewDsl (line 46) | class SimpleNewDsl < ActiveRecord::Base
  class Derivate (line 55) | class Derivate < Simple
  class DerivateNewDsl (line 58) | class DerivateNewDsl < SimpleNewDsl
  class Thief (line 61) | class Thief < ActiveRecord::Base

FILE: spec/models/process_with_new_dsl.rb
  class ProcessWithNewDsl (line 1) | class ProcessWithNewDsl
    method state (line 4) | def self.state(*args)
    method flag (line 23) | def flag
    method event (line 27) | def self.event(*args)

FILE: spec/models/silencer.rb
  class Silencer (line 1) | class Silencer

FILE: spec/models/son.rb
  class Son (line 1) | class Son < Father

FILE: spec/models/sub_classing.rb
  class SubClassing (line 1) | class SubClassing < Silencer

FILE: spec/models/this_name_better_not_be_in_use.rb
  class ThisNameBetterNotBeInUse (line 1) | class ThisNameBetterNotBeInUse

FILE: spec/models/transactor.rb
  class Transactor (line 2) | class Transactor < ActiveRecord::Base
    method start_worker (line 18) | def start_worker
    method fail (line 22) | def fail

FILE: spec/models/validator.rb
  class Validator (line 3) | class Validator < ActiveRecord::Base

FILE: spec/models/worker.rb
  class Worker (line 1) | class Worker < ActiveRecord::Base

FILE: spec/spec_helper.rb
  function load_schema (line 15) | def load_schema

FILE: spec/unit/callbacks_spec.rb
  class Foo (line 42) | class Foo
  function error_callback (line 52) | def @foo.error_callback(e); end
  function aasm_event_fired (line 74) | def @foo.aasm_event_fired(event, from, to); end
  function aasm_event_failed (line 97) | def @foo.aasm_event_failed(event, from); end

FILE: spec/unit/event_spec.rb
  function aasm_write_state (line 263) | def foo.aasm_write_state; end

FILE: spec/unit/initial_state_spec.rb
  class Banker (line 3) | class Banker
    method initialize (line 12) | def initialize(balance = 0); self.balance = balance; end
    method rich? (line 13) | def rich?; self.balance >= RICH; end

FILE: spec/unit/localizer_spec.rb
  class LocalizerTestModel (line 8) | class LocalizerTestModel < ActiveRecord::Base

FILE: spec/unit/simple_example_spec.rb
  class Payment (line 3) | class Payment

FILE: spec/unit/state_spec.rb
  function new_state (line 9) | def new_state(options={})
Condensed preview — 70 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (117K chars).
[
  {
    "path": ".document",
    "chars": 62,
    "preview": "README.rdoc\nlib/**/*.rb\nbin/*\nfeatures/**/*.feature\n-\nLICENSE\n"
  },
  {
    "path": ".gitignore",
    "chars": 98,
    "preview": "*.sw?\n*~\n.DS_Store\n.idea\ncoverage\npkg\nrdoc\nGemfile.lock\nspec/debug.log\nspec/*.db\nTODO\n.rvmrc\nalto\n"
  },
  {
    "path": ".travis.yml",
    "chars": 186,
    "preview": "language: ruby\nrvm:\n  - 1.8.7\n  - 1.9.2\n  - 1.9.3\n  - 2.0.0\n  # - jruby-18mode # JRuby in 1.8 mode\n  # - jruby-19mode # "
  },
  {
    "path": "API",
    "chars": 769,
    "preview": "\nOverwrite method to read the current state. Used to provide another storage mechanism,\ndifferent from the standard Rail"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 2538,
    "preview": "# CHANGELOG\n\n## 3.0.19\n\n * fixed deprecation warning with *Rails 4* (`Relation#update_all` with conditions is deprecated"
  },
  {
    "path": "Gemfile",
    "chars": 39,
    "preview": "source 'https://rubygems.org'\n\ngemspec\n"
  },
  {
    "path": "HOWTO",
    "chars": 139,
    "preview": "How to\n\n1. Run tests for Mongoid\n\nStart MongoDB\n\n  $> mongod\n\nRun the specs\n\n  $> rspec spec/unit/persistence/mongoid_pe"
  },
  {
    "path": "LICENSE",
    "chars": 1061,
    "preview": "Copyright (c) 2006-2012 Scott Barron\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of th"
  },
  {
    "path": "README.md",
    "chars": 9445,
    "preview": "# AASM - Ruby state machines [![Build Status](https://secure.travis-ci.org/aasm/aasm.png)](http://travis-ci.org/aasm/aas"
  },
  {
    "path": "Rakefile",
    "chars": 574,
    "preview": "require 'bundler/gem_tasks'\n\nrequire 'rspec/core'\nrequire 'rspec/core/rake_task'\nRSpec::Core::RakeTask.new(:spec) do |sp"
  },
  {
    "path": "aasm.gemspec",
    "chars": 1522,
    "preview": "# -*- encoding: utf-8 -*-\n$:.push File.expand_path(\"../lib\", __FILE__)\nrequire \"aasm/version\"\n\nGem::Specification.new do"
  },
  {
    "path": "lib/aasm/aasm.rb",
    "chars": 5921,
    "preview": "module AASM\n\n  def self.included(base) #:nodoc:\n    base.extend AASM::ClassMethods\n\n    # do not overwrite existing stat"
  },
  {
    "path": "lib/aasm/base.rb",
    "chars": 2462,
    "preview": "module AASM\n  class Base\n\n    def initialize(clazz, options={}, &block)\n      @clazz = clazz\n      @state_machine = AASM"
  },
  {
    "path": "lib/aasm/deprecated/aasm.rb",
    "chars": 423,
    "preview": "module AASM\n\n  module ClassMethods\n    def human_event_name(*args)\n      warn \"AASM.human_event_name is deprecated and w"
  },
  {
    "path": "lib/aasm/errors.rb",
    "chars": 105,
    "preview": "module AASM\n  class InvalidTransition < RuntimeError; end\n  class UndefinedState < RuntimeError; end\nend\n"
  },
  {
    "path": "lib/aasm/event.rb",
    "chars": 3610,
    "preview": "module AASM\n  class Event\n\n    attr_reader :name, :options\n\n    def initialize(name, options = {}, &block)\n      @name ="
  },
  {
    "path": "lib/aasm/instance_base.rb",
    "chars": 2649,
    "preview": "module AASM\n  class InstanceBase\n\n    def initialize(instance)\n      @instance = instance\n    end\n\n    def current_state"
  },
  {
    "path": "lib/aasm/localizer.rb",
    "chars": 1721,
    "preview": "module AASM\n  class Localizer\n    def human_event_name(klass, event)\n      checklist = ancestors_list(klass).inject([]) "
  },
  {
    "path": "lib/aasm/persistence/active_record_persistence.rb",
    "chars": 4267,
    "preview": "module AASM\n  module Persistence\n    module ActiveRecordPersistence\n      # This method:\n      #\n      # * extends the m"
  },
  {
    "path": "lib/aasm/persistence/base.rb",
    "chars": 3708,
    "preview": "module AASM\n  module Persistence\n    module Base\n\n      def self.included(base) #:nodoc:\n        base.extend ClassMethod"
  },
  {
    "path": "lib/aasm/persistence/mongoid_persistence.rb",
    "chars": 4136,
    "preview": "module AASM\n  module Persistence\n    module MongoidPersistence\n      # This method:\n      #\n      # * extends the model "
  },
  {
    "path": "lib/aasm/persistence.rb",
    "chars": 859,
    "preview": "module AASM\n  module Persistence\n    class << self\n\n      def load_persistence(base)\n        # Use a fancier auto-loadin"
  },
  {
    "path": "lib/aasm/state.rb",
    "chars": 1464,
    "preview": "module AASM\n  class State\n    attr_reader :name, :options\n\n    def initialize(name, clazz, options={})\n      @name = nam"
  },
  {
    "path": "lib/aasm/state_machine.rb",
    "chars": 877,
    "preview": "module AASM\n  class StateMachine\n\n    # the following two methods provide the storage of all state machines\n    def self"
  },
  {
    "path": "lib/aasm/transition.rb",
    "chars": 1183,
    "preview": "module AASM\n  class Transition\n    attr_reader :from, :to, :opts\n    alias_method :options, :opts\n\n    def initialize(op"
  },
  {
    "path": "lib/aasm/version.rb",
    "chars": 37,
    "preview": "module AASM\n  VERSION = \"3.0.19\"\nend\n"
  },
  {
    "path": "lib/aasm.rb",
    "chars": 399,
    "preview": "require 'ostruct'\n\n%w(\n    version\n    errors\n    base\n    instance_base\n    transition\n    event\n    state\n    localize"
  },
  {
    "path": "spec/database.yml",
    "chars": 61,
    "preview": "sqlite3:\n  adapter: sqlite3\n  database: spec/aasm.sqlite3.db\n"
  },
  {
    "path": "spec/en.yml",
    "chars": 182,
    "preview": "en:\n  activerecord:\n    events:\n      localizer_test_model:\n        close: \"Let's close it!\"\n\n    attributes:\n      loca"
  },
  {
    "path": "spec/en_deprecated_style.yml",
    "chars": 193,
    "preview": "en:\n  activerecord:\n    events:\n      localizer_test_model:\n        close: \"Let's close it!\"\n\n    attributes:\n      loca"
  },
  {
    "path": "spec/models/active_record/api.rb",
    "chars": 1548,
    "preview": "class DefaultState\n  attr_accessor :transient_store, :persisted_store\n  include AASM\n  aasm do\n    state :alpha, :initia"
  },
  {
    "path": "spec/models/argument.rb",
    "chars": 186,
    "preview": "class Argument\n  include AASM\n  aasm do\n    state :invalid, :initial => true\n    state :valid\n\n    event :valid do\n     "
  },
  {
    "path": "spec/models/auth_machine.rb",
    "chars": 1982,
    "preview": "class AuthMachine\n  include AASM\n\n  attr_accessor :activation_code, :activated_at, :deleted_at\n\n  aasm do\n    state :pas"
  },
  {
    "path": "spec/models/bar.rb",
    "chars": 177,
    "preview": "class Bar\n  include AASM\n\n  aasm do\n    state :read\n    state :ended\n\n    event :foo do\n      transitions :to => :ended,"
  },
  {
    "path": "spec/models/callback_new_dsl.rb",
    "chars": 1076,
    "preview": "class CallbackNewDsl\n  include AASM\n\n  aasm do\n    state :open, :initial => true,\n      :before_enter => :before_enter_o"
  },
  {
    "path": "spec/models/callback_old_dsl.rb",
    "chars": 1052,
    "preview": "class CallbackOldDsl\n  include AASM\n\n  aasm_initial_state :open\n  aasm_state :open,\n    :before_enter => :before_enter_o"
  },
  {
    "path": "spec/models/conversation.rb",
    "chars": 738,
    "preview": "class Conversation\n  include AASM\n\n  aasm do\n    state :needs_attention, :initial => true\n    state :read\n    state :clo"
  },
  {
    "path": "spec/models/father.rb",
    "chars": 378,
    "preview": "require 'active_record'\n\nclass Father < ActiveRecord::Base\n  include AASM\n\n  aasm do\n    state :missing_details, :initia"
  },
  {
    "path": "spec/models/foo.rb",
    "chars": 520,
    "preview": "class Foo\n  include AASM\n  aasm do\n    state :open, :initial => true, :exit => :exit\n    state :closed, :enter => :enter"
  },
  {
    "path": "spec/models/invalid_persistor.rb",
    "chars": 406,
    "preview": "require 'active_record'\n\nclass InvalidPersistor < ActiveRecord::Base\n  include AASM\n  aasm :column => :status, :skip_val"
  },
  {
    "path": "spec/models/mongoid/simple_mongoid.rb",
    "chars": 167,
    "preview": "class SimpleMongoid\n  include Mongoid::Document\n  include AASM\n\n  field :status, type: String\n\n  aasm_column :status\n  a"
  },
  {
    "path": "spec/models/mongoid/simple_new_dsl_mongoid.rb",
    "chars": 187,
    "preview": "class SimpleNewDslMongoid\n  include Mongoid::Document\n  include AASM\n\n  field :status, type: String\n\n  aasm :column => :"
  },
  {
    "path": "spec/models/not_auto_loaded/process.rb",
    "chars": 311,
    "preview": "module Models\n  class Process\n    include AASM\n\n    aasm_state :sleeping\n    aasm_state :running\n    aasm_state :suspend"
  },
  {
    "path": "spec/models/parametrised_event.rb",
    "chars": 739,
    "preview": "class ParametrisedEvent\n  include AASM\n  aasm do\n    state :sleeping, :initial => true\n    state :showering\n    state :w"
  },
  {
    "path": "spec/models/persistence.rb",
    "chars": 1248,
    "preview": "class Gate < ActiveRecord::Base\n  include AASM\n\n  # Fake this column for testing purposes\n  attr_accessor :aasm_state\n\n "
  },
  {
    "path": "spec/models/process_with_new_dsl.rb",
    "chars": 519,
    "preview": "class ProcessWithNewDsl\n  include AASM\n\n  def self.state(*args)\n    raise \"wrong state method\"\n  end\n\n  attr_accessor :f"
  },
  {
    "path": "spec/models/silencer.rb",
    "chars": 379,
    "preview": "class Silencer\n  include AASM\n\n  aasm :whiny_transitions => false do\n    state :silent, :initial => true\n    state :cryi"
  },
  {
    "path": "spec/models/son.rb",
    "chars": 38,
    "preview": "class Son < Father\n  include AASM\nend\n"
  },
  {
    "path": "spec/models/sub_classing.rb",
    "chars": 35,
    "preview": "class SubClassing < Silencer\n  \nend"
  },
  {
    "path": "spec/models/this_name_better_not_be_in_use.rb",
    "chars": 155,
    "preview": "class ThisNameBetterNotBeInUse\n  include AASM\n\n  aasm do\n    state :initial\n    state :symbol\n    state :string\n    stat"
  },
  {
    "path": "spec/models/transactor.rb",
    "chars": 483,
    "preview": "require 'active_record'\nclass Transactor < ActiveRecord::Base\n\n  belongs_to :worker\n\n  include AASM\n  aasm :column => :s"
  },
  {
    "path": "spec/models/validator.rb",
    "chars": 365,
    "preview": "require 'active_record'\n\nclass Validator < ActiveRecord::Base\n  include AASM\n  aasm :column => :status do\n    state :sle"
  },
  {
    "path": "spec/models/worker.rb",
    "chars": 38,
    "preview": "class Worker < ActiveRecord::Base\nend\n"
  },
  {
    "path": "spec/schema.rb",
    "chars": 839,
    "preview": "ActiveRecord::Schema.define(:version => 0) do\n\n  %w{gates readers writers transients simples simple_new_dsls thieves loc"
  },
  {
    "path": "spec/spec_helper.rb",
    "chars": 909,
    "preview": "$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))\n$LOAD_PATH.unshift(File.expand_path(File.join(File.dirname("
  },
  {
    "path": "spec/unit/api_spec.rb",
    "chars": 1685,
    "preview": "require 'spec_helper'\nrequire 'models/active_record/api.rb'\n\ndescribe \"reading the current state\" do\n  it \"uses the AASM"
  },
  {
    "path": "spec/unit/callbacks_spec.rb",
    "chars": 4135,
    "preview": "require 'spec_helper'\n\ndescribe 'callbacks for the old DSL' do\n  let(:callback) {CallbackOldDsl.new}\n\n  it \"should get c"
  },
  {
    "path": "spec/unit/complex_example_spec.rb",
    "chars": 1963,
    "preview": "require 'spec_helper'\n\ndescribe 'on initialization' do\n  let(:auth) {AuthMachine.new}\n\n  it 'should be in the pending st"
  },
  {
    "path": "spec/unit/event_spec.rb",
    "chars": 7908,
    "preview": "require 'spec_helper'\n\ndescribe 'adding an event' do\n  let(:event) do\n    AASM::Event.new(:close_order, {:success => :su"
  },
  {
    "path": "spec/unit/initial_state_spec.rb",
    "chars": 829,
    "preview": "require 'spec_helper'\n\nclass Banker\n  include AASM\n  aasm do\n    state :retired\n    state :selling_bad_mortgages\n  end\n "
  },
  {
    "path": "spec/unit/inspection_spec.rb",
    "chars": 3439,
    "preview": "require 'spec_helper'\n\ndescribe 'inspection for common cases' do\n  it 'should support the old DSL' do\n    Foo.should res"
  },
  {
    "path": "spec/unit/localizer_spec.rb",
    "chars": 2629,
    "preview": "require 'spec_helper'\nrequire 'active_record'\nrequire 'logger'\nrequire 'i18n'\n\nload_schema\n\nclass LocalizerTestModel < A"
  },
  {
    "path": "spec/unit/memory_leak_spec.rb",
    "chars": 1799,
    "preview": "# require 'spec_helper'\n\n# describe \"state machines\" do\n\n#   def number_of_objects(clazz)\n#     ObjectSpace.each_object("
  },
  {
    "path": "spec/unit/new_dsl_spec.rb",
    "chars": 350,
    "preview": "require 'spec_helper'\n\ndescribe \"the new dsl\" do\n\n  let(:process) {ProcessWithNewDsl.new}\n\n  it 'should not conflict wit"
  },
  {
    "path": "spec/unit/persistence/active_record_persistence_spec.rb",
    "chars": 5448,
    "preview": "require 'active_record'\nrequire 'logger'\nrequire 'spec_helper'\n\nload_schema\n\n# if you want to see the statements while r"
  },
  {
    "path": "spec/unit/persistence/mongoid_persistance_spec.rb",
    "chars": 3871,
    "preview": "describe 'mongoid', :if => Gem::Version.create(RUBY_VERSION.dup) >= Gem::Version.create('1.9.3') do\n# describe 'mongoid'"
  },
  {
    "path": "spec/unit/simple_example_spec.rb",
    "chars": 1837,
    "preview": "require 'spec_helper'\n\nclass Payment\n  include AASM\n  aasm do\n    state :initialised, :initial => true\n    state :filled"
  },
  {
    "path": "spec/unit/state_spec.rb",
    "chars": 2305,
    "preview": "require 'spec_helper'\n\ndescribe AASM::State do\n  before(:each) do\n    @name    = :astate\n    @options = { :crazy_custom_"
  },
  {
    "path": "spec/unit/subclassing_spec.rb",
    "chars": 739,
    "preview": "require 'spec_helper'\n\ndescribe 'subclassing' do\n  let(:son) {Son.new}\n\n  it 'should have the parent states' do\n    Foo."
  },
  {
    "path": "spec/unit/transition_spec.rb",
    "chars": 5133,
    "preview": "require 'spec_helper'\n\ndescribe 'transitions' do\n\n  it 'should raise an exception when whiny' do\n    process = ProcessWi"
  }
]

About this extraction

This page contains the full source code of the rubyist/aasm GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 70 files (106.7 KB), approximately 30.3k tokens, and a symbol index with 258 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!