enum_accessor 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -12,14 +12,6 @@ Add this line to your application's Gemfile.
12
12
  gem 'enum_accessor'
13
13
  ```
14
14
 
15
- Add an integer column.
16
-
17
- ```ruby
18
- create_table :users do |t|
19
- t.integer :gender, default: 0
20
- end
21
- ```
22
-
23
15
  Define `enum_accessor` in a model class.
24
16
 
25
17
  ```ruby
@@ -44,13 +36,23 @@ User.genders # => { :female => 0, :male => 1 }
44
36
  User::GENDERS # => { "female" => 0, "male" => 1 }
45
37
  ```
46
38
 
47
- Notice that zero-based numbering is used for database values.
39
+ Notice that zero-based numbering is used as database values.
40
+
41
+ Your migration should look like this.
42
+
43
+ ```ruby
44
+ create_table :users do |t|
45
+ t.integer :gender, :default => 0
46
+ end
47
+ ```
48
+
49
+ 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.
48
50
 
49
51
  ## Manual coding
50
52
 
51
- There are times when it makes more sense to manually pick particular integers for the mapping.
53
+ There are times when it makes more sense to manually pick particular integer values for the mapping.
52
54
 
53
- Just pass a hash with coded integer values.
55
+ In such cases, just pass a hash with coded integer values.
54
56
 
55
57
  ```ruby
56
58
  enum_accessor :status, ok: 200, not_found: 404, internal_server_error: 500
@@ -58,7 +60,7 @@ enum_accessor :status, ok: 200, not_found: 404, internal_server_error: 500
58
60
 
59
61
  ## Scoping query
60
62
 
61
- To retrieve internal integer values for query, use `User.genders`.
63
+ For querying purpose, use `User.genders` method to retrieve internal integer values.
62
64
 
63
65
  ```ruby
64
66
  User.where(gender: User.genders(:female))
@@ -78,34 +80,37 @@ Or skip validation entirely.
78
80
  enum_accessor :status, [ :on, :off ], validate: false
79
81
  ```
80
82
 
81
- ## i18n
83
+ ## Translation
82
84
 
83
- EnumAccessor supports i18n just as ActiveModel does.
85
+ EnumAccessor supports [i18n](http://guides.rubyonrails.org/i18n.html) just as ActiveModel does.
84
86
 
85
- Add the following lines to `config/locales/ja.yml`
87
+ For instance, create a Japanese translation in `config/locales/ja.yml`
86
88
 
87
89
  ```yaml
88
90
  ja:
89
91
  enum_accessor:
90
- user:
91
- gender:
92
- female:
93
- male: 男
92
+ gender:
93
+ female:
94
+ male:
94
95
  ```
95
96
 
96
- and now `human_*` method returns a translated string. It defaults to English nicely as well.
97
+ and now `human_*` methods return a translated string. It defaults to `humanize` method nicely as well.
97
98
 
98
99
  ```ruby
99
100
  I18n.locale = :ja
100
- user.human_gender # => '女'
101
+ user.human_gender # => '女'
102
+ User.human_genders # => { :female => '女', :male => '男' }
101
103
 
102
104
  I18n.locale = :en
103
- user.human_gender # => 'Female'
105
+ user.human_gender # => 'Female'
106
+ User.human_genders # => { :female => 'Female', :male => 'Male' }
104
107
  ```
105
108
 
106
109
  ## Why enum keys are internally stored as strings rather than symbols?
107
110
 
108
- 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.
111
+ 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.
112
+
113
+ We
109
114
 
110
115
  For the same reason, `ActiveSupport::HashWithIndifferentAccess` (which is used for `params`) keeps hash keys as string internally.
111
116
 
@@ -116,16 +121,14 @@ https://github.com/rails/rails/blob/master/activesupport/lib/active_support/hash
116
121
  There are tons of similar gems out there. Then why did I bother creating another one myself rather than sending pull requests to one of them? Because each one of them has incompatible design policies than EnumAccessor.
117
122
 
118
123
  * [simple_enum](https://github.com/lwe/simple_enum)
119
- * Pretty close to EnumAccessor feature-wise but requires `*_cd` suffix for the database column, which makes AR scopes ugly.
120
- * [enum_field](https://github.com/jamesgolick/enum_field)
121
- * Enum values are defined as top-level predicate methods, which could conflict with existing methods. Also you can't define multiple enums to the same model. In some use cases, predicate methods are not necessary and you just want to be on the safe side.
124
+ * Pretty close to EnumAccessor feature-wise but requires `*_cd` suffix for the database column, which makes AR scopes ugly.
125
+ * Enum values are defined as top-level predicate methods, which could conflict with existing methods. Also you can't define multiple enums to the same model. In some use cases, predicate methods are not necessary and you just want to be on the safe side.
122
126
  * [enumerated_attribute](https://github.com/jeffp/enumerated_attribute)
123
- * Top-level predicate methods. Many additional methods are coupled with a specific usage assumption.
127
+ * Top-level predicate methods. Many additional methods are coupled with a specific usage assumption.
128
+ * [enum_field](https://github.com/jamesgolick/enum_field)
129
+ * Top-level predicate methods.
124
130
  * [coded_options](https://github.com/jasondew/coded_options)
125
- * No support for symbols. Verbose definitions.
126
131
  * [active_enum](https://github.com/adzap/active_enum)
127
- * Syntax seems verbose.
128
132
  * [classy_enum](https://github.com/beerlington/classy_enum)
129
- * As the name suggests, class-based enum. I wanted something lighter.
130
133
 
131
134
  Also, EnumAccessor has one of the simplest code base, so that you can easily hack on.
@@ -1,3 +1,3 @@
1
1
  module EnumAccessor
2
- VERSION = '0.1.1'
2
+ VERSION = '0.2.0'
3
3
  end
data/lib/enum_accessor.rb CHANGED
@@ -26,7 +26,7 @@ module EnumAccessor
26
26
 
27
27
  # Getter
28
28
  define_method(field) do
29
- const.key(read_attribute(field)).try(:to_sym)
29
+ symbolized_enums.key(read_attribute(field))
30
30
  end
31
31
 
32
32
  # Setter
@@ -52,11 +52,17 @@ module EnumAccessor
52
52
  end
53
53
  end
54
54
 
55
+ # Class method
55
56
  class_eval(<<-EOS, __FILE__, __LINE__ + 1)
56
- def self.#{field.pluralize}(*args)
57
- return #{symbolized_enums} if args.first.nil?
58
- return #{symbolized_enums}[args.first.to_sym] if args.size == 1
59
- args.map{|arg| #{symbolized_enums}[arg.to_sym] }
57
+ def self.#{field.pluralize}(symbol = nil)
58
+ return #{symbolized_enums} if symbol.nil?
59
+ return #{symbolized_enums}[symbol]
60
+ end
61
+
62
+ def self.human_#{field.pluralize}(symbol = nil)
63
+ humanized_enums = Hash[#{symbolized_enums}.map{|k,v| [k, human_enum_accessor(:#{field}, k)] }]
64
+ return humanized_enums if symbol.nil?
65
+ return humanized_enums[symbol]
60
66
  end
61
67
  EOS
62
68
 
@@ -72,14 +78,14 @@ module EnumAccessor
72
78
  end
73
79
 
74
80
  # Mimics ActiveModel::Translation.human_attribute_name
75
- def human_enum_accessor(field, value, options = {})
81
+ def human_enum_accessor(field, key, options = {})
76
82
  defaults = lookup_ancestors.map do |klass|
77
- :"#{self.i18n_scope}.enum_accessor.#{klass.model_name.i18n_key}.#{field}.#{value}"
83
+ :"#{self.i18n_scope}.enum_accessor.#{klass.model_name.i18n_key}.#{field}.#{key}"
78
84
  end
79
- defaults << :"enum_accessor.#{self.model_name.i18n_key}.#{field}.#{value}"
80
- defaults << :"enum_accessor.#{field}.#{value}"
85
+ defaults << :"enum_accessor.#{self.model_name.i18n_key}.#{field}.#{key}"
86
+ defaults << :"enum_accessor.#{field}.#{key}"
81
87
  defaults << options.delete(:default) if options[:default]
82
- defaults << value.to_s.humanize
88
+ defaults << key.to_s.humanize
83
89
 
84
90
  options.reverse_merge! :count => 1, :default => defaults
85
91
  I18n.translate(defaults.shift, options)
@@ -38,12 +38,18 @@ describe EnumAccessor do
38
38
  @user.gender_male?.should == true
39
39
  end
40
40
 
41
- it 'adds humanized getter' do
41
+ it 'adds humanized methods' do
42
42
  I18n.locale = :ja
43
+ User.human_attribute_name(:gender).should == '性別'
43
44
  @user.human_gender.should == '女'
45
+ User.human_genders(:female).should == '女'
46
+ User.human_genders.should == { :female => '女', :male => '男' }
44
47
 
45
48
  I18n.locale = :en
49
+ User.human_attribute_name(:gender).should == 'Gender'
46
50
  @user.human_gender.should == 'Female'
51
+ User.human_genders(:female).should == 'Female'
52
+ User.human_genders.should == { :female => 'Female', :male => 'Male' }
47
53
  end
48
54
 
49
55
  it 'defines internal constant' do
data/spec/locales.yml CHANGED
@@ -1,6 +1,9 @@
1
1
  ja:
2
+ activerecord:
3
+ attributes:
4
+ user:
5
+ gender: 性別
2
6
  enum_accessor:
3
- user:
4
- gender:
5
- female:
6
- male: 男
7
+ gender:
8
+ female:
9
+ male:
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: enum_accessor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: