Manhattan is a gem extracted from the practices we used at Xenda in the development of our projects.
It strives to be a simple status manager for models with minimal overhead and allowing the creation of a simple state machine. Most projects in our experience need for a model to hold a status at once and to perform some actions before or after obtaining that state. This gem simplifies that work without adding much overhead.
Add this line to your application's Gemfile:
gem 'manhattan'
And then execute:
$ bundle
Or install it yourself as:
$ gem install manhattan
Models that want to be handled by Manhattan should include the gem on their definition:
class ComicBook < ActiveRecord::Base
include Manhattan
end
Manhattan will then wait for your to describe the list of states your class can hold:
class ComicBook < ActiveRecord::Base
include Manhattan
has_statuses :opened, :sold
end
For it to do its work, it'll assume the model has a "status" column of type string on your database. This can be customized by appending the "column_name" key at the end of your states list:
class ComicBook < ActiveRecord::Base
include Manhattan
has_statuses :opened, :sold, column_name: :state
end
Manhattan will even allow you to setup a default state for initialized records. Take notice that this shouldn't be used instead of setting a default value on a migration or directly on your column.
After this setup, Manhattan will give you some love in the form of code
ComicBook.statuses #=> ["opened", "sold"]
ComicBook.new.statuses #=> ["opened", "sold"]
comic_book = ComicBook.new
comic_book.mark_as_opened
comic_book.status #=> "opened"
# directly asking for status
comic_book.opened? #=> "true"
comic_book.sold? #=> "false"
# or even asking about its negative
comic_book.unopened? #=> "false"
comic_book.not_sold? #=> "true"
Manhattan will create alias like "invalid" "unsold" and "not_valid" for each state. Use whichever feels natural for your code.
Manhattan will look for before_* and after_* methods for each state. If they exist, it will run them accordingly:
class ComicBook < ActiveRecord::Base
# .... all the above code
def before_opened
puts "This is a sad day... when this comic loses its value"
end
def after_opened
puts "WE CRY NOW AND SHIVER FOR IT'S NO LONGER COLLECTABLE"
end
comic_book.mark_as_opened #=>
#"This is a sad day... when this comic loses its value"
#"WE CRY NOW AND SHIVER FOR IT'S NO LONGER COLLECTABLE"
Each model class has associated scopes created for easy returning records from the DB for each state:
ComicBook.opened #=> select * from comic_books where status = 'opened'
If wanted, you can setup a default state for your model
class ComicBook < ActiveRecord::Base
include Manhattan
has_statuses :opened, :sold, default_value: :opened
end
ComicBook.new.status #=> "opened"
Fairly simple, but I18N is pending.
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request