Permalink
Browse files

Added class-level human methods. Bump to 0.2.0

  • Loading branch information...
1 parent b554eb5 commit 30a287e1abcb48d9b28278974cc7f7882133ad22 @kenn committed Sep 17, 2012
Showing with 59 additions and 39 deletions.
  1. +28 −23 README.md
  2. +16 −10 lib/enum_accessor.rb
  3. +1 −1 lib/enum_accessor/version.rb
  4. +7 −1 spec/enum_accessor_spec.rb
  5. +7 −4 spec/locales.yml
View
@@ -12,14 +12,6 @@ Add this line to your application's Gemfile.
gem 'enum_accessor'
```
-Add an integer column.
-
-```ruby
-create_table :users do |t|
- t.integer :gender, default: 0
-end
-```
-
Define `enum_accessor` in a model class.
```ruby
@@ -44,21 +36,31 @@ User.genders # => { :female => 0, :male => 1 }
User::GENDERS # => { "female" => 0, "male" => 1 }
```
-Notice that zero-based numbering is used for database values.
+Notice that zero-based numbering is used as database values.
+
+Your migration should look like this.
+
+```ruby
+create_table :users do |t|
+ t.integer :gender, :default => 0
+end
+```
+
+Optionally, it would be a good idea to add `:limit => 1` on the column for even better space efficiency when the enum set is small.
## Manual coding
-There are times when it makes more sense to manually pick particular integers for the mapping.
+There are times when it makes more sense to manually pick particular integer values for the mapping.
-Just pass a hash with coded integer values.
+In such cases, just pass a hash with coded integer values.
```ruby
enum_accessor :status, ok: 200, not_found: 404, internal_server_error: 500
```
## Scoping query
-To retrieve internal integer values for query, use `User.genders`.
+For querying purpose, use `User.genders` method to retrieve internal integer values.
```ruby
User.where(gender: User.genders(:female))
@@ -78,34 +80,37 @@ Or skip validation entirely.
enum_accessor :status, [ :on, :off ], validate: false
```
-## i18n
+## Translation
-EnumAccessor supports i18n just as ActiveModel does.
+EnumAccessor supports [i18n](http://guides.rubyonrails.org/i18n.html) just as ActiveModel does.
-Add the following lines to `config/locales/ja.yml`
+For instance, create a Japanese translation in `config/locales/ja.yml`
```yaml
ja:
enum_accessor:
- user:
- gender:
- female:
- male:
+ gender:
+ female:
+ male:
```
-and now `human_*` method returns a translated string. It defaults to English nicely as well.
+and now `human_*` methods return a translated string. It defaults to `humanize` method nicely as well.
```ruby
I18n.locale = :ja
-user.human_gender # => '女'
+user.human_gender # => '女'
+User.human_genders # => { :female => '女', :male => '男' }
I18n.locale = :en
-user.human_gender # => 'Female'
+user.human_gender # => 'Female'
+User.human_genders # => { :female => 'Female', :male => 'Male' }
```
## Why enum keys are internally stored as strings rather than symbols?
-Because `params[:gender].to_sym` is dangerous. It could be a source of problems like memory leak, slow symbol table lookup, or even DoS attack. If a user sends random strings for the parameter, it generates unlimited number of symbols, which can never be garbage collected, and eventually causes `symbol table overflow (RuntimeError)`, eating up gigabytes of memory.
+Because `params[:gender].to_sym` is dangerous. It could lead to problems like memory leak, slow symbol table lookup, or even DoS attack. If a user sends random strings for the parameter, it generates uncontrollable number of symbols, which can never be garbage collected, and eventually causes `symbol table overflow (RuntimeError)`, eating up gigabytes of memory.
+
+We
For the same reason, `ActiveSupport::HashWithIndifferentAccess` (which is used for `params`) keeps hash keys as string internally.
View
@@ -26,7 +26,7 @@ def enum_accessor(field, enums, options={})
# Getter
define_method(field) do
- const.key(read_attribute(field)).try(:to_sym)
+ symbolized_enums.key(read_attribute(field))
end
# Setter
@@ -52,11 +52,17 @@ def enum_accessor(field, enums, options={})
end
end
+ # Class method
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
- def self.#{field.pluralize}(*args)
- return #{symbolized_enums} if args.first.nil?
- return #{symbolized_enums}[args.first.to_sym] if args.size == 1
- args.map{|arg| #{symbolized_enums}[arg.to_sym] }
+ def self.#{field.pluralize}(symbol = nil)
+ return #{symbolized_enums} if symbol.nil?
+ return #{symbolized_enums}[symbol]
+ end
+
+ def self.human_#{field.pluralize}(symbol = nil)
+ humanized_enums = Hash[#{symbolized_enums}.map{|k,v| [k, human_enum_accessor(:#{field}, k)] }]
+ return humanized_enums if symbol.nil?
+ return humanized_enums[symbol]
end
EOS
@@ -72,14 +78,14 @@ def self.#{field.pluralize}(*args)
end
# Mimics ActiveModel::Translation.human_attribute_name
- def human_enum_accessor(field, value, options = {})
+ def human_enum_accessor(field, key, options = {})
defaults = lookup_ancestors.map do |klass|
- :"#{self.i18n_scope}.enum_accessor.#{klass.model_name.i18n_key}.#{field}.#{value}"
+ :"#{self.i18n_scope}.enum_accessor.#{klass.model_name.i18n_key}.#{field}.#{key}"
end
- defaults << :"enum_accessor.#{self.model_name.i18n_key}.#{field}.#{value}"
- defaults << :"enum_accessor.#{field}.#{value}"
+ defaults << :"enum_accessor.#{self.model_name.i18n_key}.#{field}.#{key}"
+ defaults << :"enum_accessor.#{field}.#{key}"
defaults << options.delete(:default) if options[:default]
- defaults << value.to_s.humanize
+ defaults << key.to_s.humanize
options.reverse_merge! :count => 1, :default => defaults
I18n.translate(defaults.shift, options)
@@ -1,3 +1,3 @@
module EnumAccessor
- VERSION = '0.1.1'
+ VERSION = '0.2.0'
end
@@ -38,12 +38,18 @@ class User < ActiveRecord::Base
@user.gender_male?.should == true
end
- it 'adds humanized getter' do
+ it 'adds humanized methods' do
I18n.locale = :ja
+ User.human_attribute_name(:gender).should == '性別'
@user.human_gender.should == ''
+ User.human_genders(:female).should == ''
+ User.human_genders.should == { :female => '', :male => '' }
I18n.locale = :en
+ User.human_attribute_name(:gender).should == 'Gender'
@user.human_gender.should == 'Female'
+ User.human_genders(:female).should == 'Female'
+ User.human_genders.should == { :female => 'Female', :male => 'Male' }
end
it 'defines internal constant' do
View
@@ -1,6 +1,9 @@
ja:
+ activerecord:
+ attributes:
+ user:
+ gender: 性別
enum_accessor:
- user:
- gender:
- female:
- male:
+ gender:
+ female:
+ male:

0 comments on commit 30a287e

Please sign in to comment.