README.rdoc in enumerate_it-0.7.3 vs README.rdoc in enumerate_it-0.7.4

- old
+ new

@@ -4,45 +4,45 @@ == Description Ok, I know there are a lot of different solutions to this problem. But none of them solved my problem, so here's EnumerateIt. I needed to build a Rails application around a legacy database and this database was -filled with those small, unchangeable tables used to create foreign key constraints everywhere. +filled with those small, unchangeable tables used to create foreign key constraints everywhere. === For example: - Table "public.relationshipstatus" - Column | Type | Modifiers - -------------+---------------+----------- - code | character(1) | not null - description | character(11) | - Indexes: - "relationshipstatus_pkey" PRIMARY KEY, btree (code) + Table "public.relationshipstatus" + Column | Type | Modifiers + -------------+---------------+----------- + code | character(1) | not null + description | character(11) | + Indexes: + "relationshipstatus_pkey" PRIMARY KEY, btree (code) - select * from relationshipstatus; - code | description - -------+-------------- - 1 | Single - 2 | Married - 3 | Widow - 4 | Divorced + select * from relationshipstatus; + code | description + -------+-------------- + 1 | Single + 2 | Married + 3 | Widow + 4 | Divorced -And then I had things like a people table with a 'relationship_status' column with a foreign key +And then I had things like a people table with a 'relationship_status' column with a foreign key pointing to the relationshipstatus table. While this is a good thing from the database normalization perspective, managing this values in -my tests was very hard. Doing database joins just to get the description of some value was absurd. -And, more than this, referencing them in my code using magic numbers was terrible and meaningless: +my tests was very hard. Doing database joins just to get the description of some value was absurd. +And, more than this, referencing them in my code using magic numbers was terrible and meaningless: What does it mean when we say that someone or something is '2'? Enter EnumerateIt. == Creating enumerations -Enumerations are created as models, but you can put then anywhere in your application. In Rails -applications, you can put them inside models/. +Enumerations are created as models, but you can put then anywhere in your application. In Rails +applications, you can put them inside models/. class RelationshipStatus < EnumerateIt::Base associate_values( :single => [1, 'Single'], :married => [2, 'Married'], @@ -64,11 +64,11 @@ * You can get an array of options, ready to use with the 'select', 'select_tag', etc family of Rails helpers. RelationshipStatus.to_a # [["Divorced", 4],["Married", 2],["Single", 1],["Widow", 3]] -* You can retrieve a list with values for a group of enumeration constants. +* You can retrieve a list with values for a group of enumeration constants. RelationshipStatus.values_for %w(MARRIED SINGLE) # [2, 1] * You can manipulate the hash used to create the enumeration: @@ -84,13 +84,13 @@ attr_accessor :relationship_status has_enumeration_for :relationship_status, :with => RelationshipStatus end -The :with option is not required. If you ommit it, EnumerateIt will try to load an enumeration class based on the camelized attribute name. +The :with option is not required. If you ommit it, EnumerateIt will try to load an enumeration class based on the camelized attribute name. -This will create: +This will create: * A humanized description for the values of the enumerated attribute: p = Person.new p.relationship_status = RelationshipStatus::DIVORCED @@ -100,17 +100,21 @@ class RelationshipStatus < EnumerateIt::Base associate_values( :married => 1, :single => 2 - ) + ) end p = Person.new p.relationship_status = RelationshipStatus::MARRIED p.relationship_status_humanize # => 'Married' +* The associated enumerations can be retrieved with the 'enumerations' class method. + + Person.enumerations[:relationship_status] # => RelationshipStatus + * If you pass the :create_helpers option as 'true', it will create a helper method for each enumeration option (this option defaults to false): class Person < ActiveRecord::Base has_enumeration_for :relationship_status, :with => RelationshipStatus, :create_helpers => true end @@ -118,10 +122,21 @@ p = Person.new p.relationship_status = RelationshipStatus::MARRIED p.married? #=> true p.divorced? #=> false +* The :create_helpers also creates some mutator helper methods, that can be used to change the attribute's value. + + class Person < ActiveRecord::Base + has_enumeration_for :relationship_status, :with => RelationshipStatus, :create_helpers => true + end + + p = Person.new + p.married! + p.married? #=> true + p.divorced? #=> false + * If your class can manage validations and responds to :validates_inclusion_of, it will create this validation: class Person < ActiveRecord::Base has_enumeration_for :relationship_status, :with => RelationshipStatus end @@ -139,11 +154,11 @@ p = Person.new :relationship_status => nil p.valid? # => false p.errors[:relationship_status] # => "can't be blank" -Remember that in Rails 3 you can add validations to any kind of class and not only to those derived from +Remember that in Rails 3 you can add validations to any kind of class and not only to those derived from ActiveRecord::Base. == I18n I18n lookup is provided on both '_humanized' and 'Enumeration#to_a' methods, given the hash key is a Symbol. The I18n strings are @@ -160,20 +175,20 @@ # your locale file pt: enumerations: relationship_status: married: Casado - + p = Person.new p.relationship_status = RelationshipStatus::MARRIED - p.relationship_status_humanize # => 'Casado' - + p.relationship_status_humanize # => 'Casado' + p.relationship_status = RelationshipStatus::SINGLE - p.relationship_status_humanize # => 'Single' => nonexistent key - + p.relationship_status_humanize # => 'Single' => nonexistent key + p.relationship_status = RelationshipStatus::DIVORCED - p.relationship_status_humanize # => 'He's divorced' => uses the provided string + p.relationship_status_humanize # => 'He's divorced' => uses the provided string You can also translate specific values: RelationshipStatis.t(1) # => 'Casado' @@ -183,11 +198,11 @@ == Using with Rails * Create an initializer with the following code: - ActiveRecord::Base.send :include, EnumerateIt + ActiveRecord::Base.send :include, EnumerateIt * Add the 'enumerate_it' gem as a dependency in your environment.rb (Rails 2.3.x) or Gemfile (if you're using Bundler) An interesting approach to use it in Rails apps is to create an app/models/enumerations folder and add it to your autoload path in config/application.rb: @@ -199,23 +214,36 @@ == Ruby 1.9 EnumerateIt is fully compatible with Ruby 1.9.1 and 1.9.2 (all tests pass) +* Note: on ruby 1.9.2, if you are using the enumerations in a separate folder like app/models/enumerations, and have to use the :with parameter, you have to clear the enum class namespace to a global scope by using ::EnumClass instead of EnumClass: + + # 1.8.7 + class Person < ActiveRecord::Base + has_enumeration_for :relationship_status, :with => EnumClass + end + + # 1.9.2 + class Person < ActiveRecord::Base + has_enumeration_for :relationship_status, :with => ::EnumClass + end + + == Why did you reinvent the wheel? There are other similar solutions to the problem out there, but I could not find one that -worked both with strings and integers as the enumerations' codes. I had both situations in -my legacy database. +worked both with strings and integers as the enumerations' codes. I had both situations in +my legacy database. == Why defining enumerations outside the class that use it? * I think it's cleaner. * You can add behaviour to the enumeration class. * You can reuse the enumeration inside other classes. == Note on Patches/Pull Requests - + * Fork the project. * Make your feature addition or bug fix. * Add tests for it. This is important so I don't break it in a future version unintentionally. * Commit, do not mess with rakefile, version, or history.