diff --git a/LICENSE b/LICENSE index dd12741..e1c895c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,7 @@ -Copyright (c) 2005 Trevor Squires +Initial Version Copyright (c) 2005 Trevor Squires +Rails 3 Updates Copyright (c) 2010 Pivotal Labs +Initial Test Suite Copyright (c) 2011 Sergey Potapov +Subsequent Updates Copyright (c) 2011 Arthur Shagall Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/README.md b/README.md index dd4c9d5..93a8b79 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,8 @@ It allows you to cleanly solve many of the problems that the traditional Rails a It is particularly suitable for scenarios where your Rails application is not the only user of the database, such as when it's used for analytics or reporting. -Power Enum is built on top of the Rails 3 modernization made by the fine folks at Protocool https://github.com/protocool/enumerations_mixin -to the original plugin by Trevor Squires located at https://github.com/protocool/enumerations_mixin. While many of the core ideas remain, +Power Enum is built on top of the Rails 3 modernization made by the fine folks at Protocool https://github.com/protocool/enumerations\_mixin +to the original plugin by Trevor Squires located at https://github.com/protocool/enumerations\_mixin. While many of the core ideas remain, it has been reworked and a full test suite written to facilitate further development. At it's most basic level, it allows you to say things along the lines of: @@ -39,17 +39,18 @@ then run This package adds two mixins and a helper to Rails' ActiveRecord, as well as methods to migrations to simplify the creation of backing tables. -acts_as_enumerated provides capabilities to treat your model and its records as an enumeration. -At a minimum, the database table for an acts_as_enumerated must contain an 'id' column and a 'name' column. -It is strongly recommended that there be a NOT NULL constraint on the 'name' column. -All instances for the acts_as_enumerated model are cached in memory. If the table has an 'active' column, the -value of that attribute will be used to determine which enum instances are active. Otherwise, all values are considered -active. +`acts_as_enumerated` provides capabilities to treat your model and its records as an enumeration. +At a minimum, the database table for an acts\_as\_enumerated must contain an 'id' column and a column +to hold the value of the enum ('name' by default). It is strongly recommended that there be +a NOT NULL constraint on the 'name' column. All instances for the `acts_as_enumerated` model +are cached in memory. If the table has an 'active' column, the value of that attribute +will be used to determine which enum instances are active. +Otherwise, all values are considered active. -has_enumerated adds methods to your ActiveRecord model for setting and retrieving enumerated values using an associated acts_as_enumerated model. +`has_enumerated` adds methods to your ActiveRecord model for setting and retrieving enumerated values using an associated acts\_as\_enumerated model. -There is also an ActiveRecord::VirtualEnumerations helper module to create 'virtual' acts_as_enumerated models which helps to avoid -cluttering up your models directory with acts_as_enumerated classes. +There is also an `ActiveRecord::VirtualEnumerations` helper module to create 'virtual' acts\_as\_enumerated models which helps to avoid +cluttering up your models directory with acts\_as\_enumerated classes. ## How to use it @@ -78,13 +79,13 @@ There are two methods added to Rails migrations: ##### `create_enum(enum_name, options = {})` -Creates a new enum table. enum_name will be automatically pluralized. The following options are supported: +Creates a new enum table. `enum_name` will be automatically pluralized. The following options are supported: - [:name_column] Specify the column name for name of the enum. By default it's :name. This can be a String or a Symbol -- [:description] Set this to true to have a 'description' column generated. +- [:description] Set this to `true` to have a 'description' column generated. - [:name_limit] Set this define the limit of the name column. - [:desc_limit] Set this to define the limit of the description column -- [:active] Set this to true to have a boolean 'active' column generated. The 'active' column will have the options of NOT NULL and DEFAULT TRUE. +- [:active] Set this to `true` to have a boolean 'active' column generated. The 'active' column will have the options of NOT NULL and DEFAULT TRUE. Example: @@ -105,7 +106,7 @@ is the equivalent of ##### `remove_enum(enum_name)` -Drops the enum table. enum_name will be automatically pluralized. +Drops the enum table. `enum_name` will be automatically pluralized. Example: @@ -115,13 +116,13 @@ is the equivalent of drop_table :booking_statuses -### acts_as_enumerated +### acts\_as\_enumerated class BookingStatus < ActiveRecord::Base - acts_as_enumerated :conditions => 'optional_sql_conditions', - :order => 'optional_sql_orderby', - :on_lookup_failure => :optional_class_method, - :name_column => 'optional_name_column' #If required, may override the default name column + acts_as_enumerated :conditions => 'optional_sql_conditions', + :order => 'optional_sql_orderby', + :on_lookup_failure => :optional_class_method, + :name_column => 'optional_name_column' #If required, may override the default name column end With that, your BookingStatus class will have the following methods defined: @@ -130,23 +131,29 @@ With that, your BookingStatus class will have the following methods defined: ##### `[](arg)` -BookingStatus[arg] performs a lookup the BookingStatus instance for arg. The arg value can be a 'string' or a :symbol, in which case the lookup will be against the BookingStatus.name field. Alternatively arg can be a Fixnum, in which case the lookup will be against the BookingStatus.id field. +`BookingStatus[arg]` performs a lookup for the BookingStatus instance for the given arg. The arg value can be a 'string' or a :symbol, +in which case the lookup will be against the BookingStatus.name field. Alternatively arg can be a Fixnum, +in which case the lookup will be against the BookingStatus.id field. -The :on_lookup_failure option specifies the name of a class method to invoke when the [] method is unable to locate a BookingStatus record for arg. The default is the built-in :enforce_none which returns nil. There are also built-ins for :enforce_strict (raise and exception regardless of the type for arg), :enforce_strict_literals (raises an exception if the arg is a Fixnum or Symbol), :enforce_strict_ids (raises and exception if the arg is a Fixnum) and :enforce_strict_symbols (raises an exception if the arg is a Symbol). +The `:on_lookup_failure` option specifies the name of a *class* method to invoke when the `[]` method is unable to locate a BookingStatus record for arg. +The default is the built-in `:enforce_none` which returns nil. There are also built-ins for `:enforce_strict` (raise and exception regardless of the type for arg), +`:enforce_strict_literals` (raises an exception if the arg is a Fixnum or Symbol), `:enforce_strict_ids` (raises and exception if the arg is a Fixnum) +and `:enforce_strict_symbols` (raises an exception if the arg is a Symbol). -The purpose of the :on_lookup_failure option is that a) under some circumstances a lookup failure is a Bad Thing and action should be taken, therefore b) a fallback action should be easily configurable. +The purpose of the `:on_lookup_failure` option is that a) under some circumstances a lookup failure is a Bad Thing and action should be taken, +therefore b) a fallback action should be easily configurable. ##### `all` -BookingStatus.all returns an array of all BookingStatus records that match the :conditions specified in acts_as_enumerated, in the order specified by :order. +`BookingStatus.all` returns an array of all BookingStatus records that match the `:conditions` specified in `acts_as_enumerated`, in the order specified by `:order`. ##### `active` -BookingStatus.active returns an array of all BookingStatus records that are marked active. See the active? instance method. +`BookingStatus.active` returns an array of all BookingStatus records that are marked active. See the `active?` instance method. ##### `inactive` -BookingStatus.inactive returns an array of all BookingStatus records that are inactive. See the inactive? instance method. +`BookingStatus.inactive` returns an array of all BookingStatus records that are inactive. See the `inactive?` instance method. #### Instance Methods @@ -154,38 +161,40 @@ Each enumeration model gets the following instance methods. ##### `===(arg)` -BookingStatus[:foo] === arg returns true if BookingStatus[:foo] === BookingStatus[arg] returns true if arg is Fixnum, String, or Symbol. If arg is an Array, will compare every element of the array and return true if any element return true for ===. +`BookingStatus[:foo] === arg` returns true if `BookingStatus[:foo] === BookingStatus[arg]` returns true if arg is Fixnum, String, +or Symbol. If arg is an Array, will compare every element of the array and return true if any element return true for `===`. -You should note that defining an :on_lookup_failure method that raises an exception will cause === to also raise an exception for any lookup failure of BookingStatus. +You should note that defining an `:on_lookup_failure` method that raises an exception will cause `===` to also raise an exception for any lookup failure of `BookingStatus[arg]`. -like? is aliased to === +`like?` is aliased to `===` ##### `in?(*list)` -Returns true if any element in the list returns true for ===(arg), false otherwise. +Returns true if any element in the list returns true for `===(arg)`, false otherwise. ##### `name` -Returns the 'name' of the enum, i.e. the value in the :name_column attribute of the enumeration model. +Returns the 'name' of the enum, i.e. the value in the `:name_column` attribute of the enumeration model. ##### `name_sym` -Returns the symbol representation of the name of the enum. BookingStatus[:foo].name_sym returns :foo. +Returns the symbol representation of the name of the enum. `BookingStatus[:foo].name_sym` returns :foo. ##### `active?` Returns true if the instance is active, false otherwise. If it has an attribute 'active', -returns the attribute cast to a boolean, otherwise returns true. This method is used by the 'active' +returns the attribute cast to a boolean, otherwise returns true. This method is used by the `active` class method to select active enums. ##### `inactive?` -Returns true if the instance is inactive, false otherwise. Default implementations returns !active? -This method is used by the 'inactive' class method to select inactive enums. +Returns true if the instance is inactive, false otherwise. Default implementations returns `!active?` +This method is used by the `inactive` class method to select inactive enums. #### Notes -acts_as_enumerated records are considered immutable. By default you cannot create/alter/destroy instances because they are cached in memory. Because of Rails' process-based model it is not safe to allow updating acts_as_enumerated records as the caches will get out of sync. +`acts_as_enumerated` records are considered immutable. By default you cannot create/alter/destroy instances because they are cached in memory. +Because of Rails' process-based model it is not safe to allow updating acts\_as\_enumerated records as the caches will get out of sync. However, one instance where updating the models *should* be allowed is if you are using seeds.rb to seed initial values into the database. @@ -196,19 +205,22 @@ Using the above example you would do the following: BookingStatus.create( :name => status_name ) end -A :presence and :uniqueness validation is automatically defined on each model. +Note that a `:presence` and `:uniqueness` validation is automatically defined on each model for the name column. -### has_enumerated +### has\_enumerated -First of all, note that you *could* specify the relationship to an acts_as_enumerated class using the belongs_to association. However, has_enumerated is preferable because you aren't really associated to the enumerated value, you are *aggregating* it. As such, the has_enumerated macro behaves more like an aggregation than an association. +First of all, note that you *could* specify the relationship to an `acts_as_enumerated` class using the belongs_to association. +However, `has_enumerated` is preferable because you aren't really associated to the enumerated value, you are *aggregating* it. As such, +the `has_enumerated` macro behaves more like an aggregation than an association. class Booking < ActiveRecord::Base - has_enumerated :status, :class_name => 'BookingStatus', - :foreign_key => 'status_id', - :on_lookup_failure => :optional_instance_method + has_enumerated :status, :class_name => 'BookingStatus', + :foreign_key => 'status_id', + :on_lookup_failure => :optional_instance_method end -By default, the foreign key is interpreted to be the name of your has_enumerated field (in this case 'status') plus '_id'. Additionally, the default value for :class_name is the camel-ized version of the name for your has_enumerated field. :on_lookup_failure is explained below. +By default, the foreign key is interpreted to be the name of your has\_enumerated field (in this case 'status') plus '\_id'. Additionally, +the default value for `:class_name` is the camel-ized version of the name for your has\_enumerated field. `:on_lookup_failure` is explained below. With that, your Booking class will have the following methods defined: @@ -218,42 +230,51 @@ Returns the BookingStatus with an id that matches the value in the Booking.statu #### `status=(arg)` -Sets the value for Booking.status_id using the id of the BookingStatus instance passed as an argument. As a short-hand, you can also pass it the 'name' of a BookingStatus instance, either as a 'string' or :symbol, or pass in the id directly. +Sets the value for Booking.status_id using the id of the BookingStatus instance passed as an argument. As a +short-hand, you can also pass it the 'name' of a BookingStatus instance, either as a 'string' or :symbol, or pass in the id directly. example: mybooking.status = :confirmed -this also works: +this is equivalent to: mybooking.status = 'confirmed' -The :on_lookup_failure option in has_enumerated is there because you may want to create an error handler for situations where the argument passed to status= is invalid. By default, an invalid value will cause an ArgumentError to be raised. +or: + + mybooking.status = BookingStatus[:confirmed] + +The `:on_lookup_failure` option in has_enumerated is there because you may want to create an error handler for situations +where the argument passed to `status=(arg)` is invalid. By default, an invalid value will cause an ArgumentError to be raised. Of course, this may not be optimal in your situation. In this case you can specify an *instance* method to be called in the case of a lookup failure. The method signature is as follows: your_lookup_handler(operation, name, name_foreign_key, acts_enumerated_class_name, lookup_value) -The 'operation' arg will be either :read or :write. In the case of :read you are expected to return something or raise an exception, while in the case of a :write you don't have to return anything. +The 'operation' arg will be either `:read` or `:write`. In the case of `:read` you are expected to return something or raise an exception, +while in the case of a `:write` you don't have to return anything. -Note that there's enough information in the method signature that you can specify one method to handle all lookup failures for all has_enumerated fields if you happen to have more than one defined in your model. +Note that there's enough information in the method signature that you can specify one method to handle all lookup failures +for all has\_enumerated fields if you happen to have more than one defined in your model. -NOTE: A nil is always considered to be a valid value for status= since it's assumed you're trying to null out the foreign key, therefore the :on_lookup_failure will be bypassed. +NOTE: A `nil` is always considered to be a valid value for `status=(arg)` since it's assumed you're trying to null out the foreign key. +The `:on_lookup_failure` will be bypassed. ### ActiveRecord::VirtualEnumerations -For the most part, your acts_as_enumerated classes will do nothing more than just act as enumerated. +In many instances, your `acts_as_enumerated` classes will do nothing more than just act as enumerated. In that case there isn't much point cluttering up your models directory with those class files. You can use ActiveRecord::VirtualEnumerations to reduce that clutter. -Copy virtual_enumerations_sample.rb to Rails.root/config/initializers/virtual_enumerations.rb and configure it accordingly. +Copy virtual\_enumerations\_sample.rb to Rails.root/config/initializers/virtual\_enumerations.rb and configure it accordingly. -See virtual_enumerations_sample.rb in the examples directory of this gem for a full description. +See virtual\_enumerations\_sample.rb in the examples directory of this gem for a full description. ## How to run tests -Go to dummy project: +Go to the 'dummy' project: cd ./spec/dummy @@ -277,7 +298,7 @@ And finally run tests: * Initial Version Copyright (c) 2005 Trevor Squires * Rails 3 Updates Copyright (c) 2010 Pivotal Labs -* Initial test suite Copyright (c) 2011 Sergey Potapov -* Additional Updates Copyright (c) 2011 Arthur Shagall +* Initial Test Suite Copyright (c) 2011 Sergey Potapov +* Subsequent Updates Copyright (c) 2011 Arthur Shagall Released under the MIT License. See the LICENSE file for more details.