Skip to content

Single-file state machine for Ruby. Yes, another one.

Notifications You must be signed in to change notification settings

tomas/solidstate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

27 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SolidState

Minuscule but solid state machine for Ruby classes. The only dependency is that your model responds to a getter and setter for state.

Installation

In your Gemfile:

gem 'solidstate'

Usage

  # simplest example, using just an accessor
  class Post
    include SolidState

    attr_accessor :state
    states :draft, :published
  end

  # in its simplest form you just declare the possible states.
  # if it's a simple class you just get boolean methods for checking
  # whether the current status is X or Y.

  p = Post.new
  p.state      # => nil 
  p.state = 'draft'
  p.draft?     # true
  p.published? # => false
  p.state = 'published'
  p.published? # => true
  
  # you also have access to the list of possible states at Class.states, 
  # in case you need to enumerate them.
  # for instance, to populate a select field's options, you'd do something like:

  options = Post.states.map { |st| "<option value='#{st}'>#{st}</option>" }.join("\n")

  # now, if the model class responds to validates_inclusion_of, it will
  # mark the record invalid if an unknown state is set.

  # let's assume this is actually an ActiveRecord class, and the
  # table contains a column named 'state'.

  class Post < ActiveRecord::Base
    include SolidState

    states :draft, :published
  end

  p = Post.new
  p.state = 'published'
  p.valid?  # => true
  p.state = 'deleted'
  p.valid?  # => false

  # you also get scopes for free if the class responds_to the `scope` method
  
  Post.published.first # => #<Post ...>
  Post.draft.count # => 1

  # ok, now let's gets get fancier. we're going to declare transitions
  # which will govern the possible directions in which an object's state
  # can move to.

  class Subscriber < ActiveRecord::Base
    include SolidState

    states :inactive, :active, :unsubscribed, :disabled do
      transitions from: :inactive, to: :active
      transitions from: :active, to: [:unsubscribed, :disabled]
      transitions from: :unsubscribed, to: :active
    end
  end

  s = Subscriber.new
  s.state # => 'inactive'

  # since we declared transitions, we can now call #{state}! which
  # checks whether the instance can transition to that state and
  # if so, sets the new state and optionally saves the record.

  s.active! # => true
  s.state   # => 'active'
  s.inactive! # => raises InvalidTransitionError

  # this also works outside transition methods, of course.

  s.reload  # => true
  s.active? # => true

  s.state = 'inactive'
  s.valid? # => false

  # the last trick this library does is that it optionally lets you
  # declare callback methods that are called whenever a transition
  # method succeeds. just define a method called #once_[state] in
  # your model.

  class Subscriber
    def once_unsubscribed
      puts "Sorry to see you go!"
    end
  end

  # ...
  s.unsubscribed! # => prints "Sorry to see you go!"

That's about it. For examples check the examples directory in this repo.

Contributions

You're more than welcome. Send a pull request, including tests, and make sure you don't break anything. That's it.

Author

Tomás Pollak

Copyright

(c) Fork Limited. MIT license.

About

Single-file state machine for Ruby. Yes, another one.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages