symbolize 3.3.0pre → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.rdoc CHANGED
@@ -1,52 +1,34 @@
1
- = Symbolize attribute values in ActiveRecord (e.g. for nicer enums)
2
-
3
- This plugin introduces an easy way to use symbols for values of ActiveRecord
4
- attributes. Symbolized attributes return a ruby symbol (or nil) as their value
5
- and can be set using symbols.
6
-
7
-
8
- == About
9
-
10
- Since ActiveRecord does not natively support database column types of ENUM or
11
- SET, you'll usually use a string attribute and restrict it to certain values
12
- with validations. Using this plugin, the values of such pseudo-enums are
13
- symbols, which look more ruby-style than strings.
14
-
15
- Simply add "symbolize :attr_name" to your model class, and the specified
16
- attribute will return symbol values and can be set using smbols (setting
17
- string values will still work, which is important when using forms).
18
-
19
- An attribute to symbolize should be a string (varchar) column in the database.
20
-
21
- Blog: http://zargony.com/
22
- Github: http://github.com/zargony/activerecord_symbolize
1
+ = Symbolize attribute values
23
2
 
3
+ This plugin introduces an easy way to use symbols for values of attributes. Symbolized attributes return a ruby symbol (or nil) as their value
4
+ and can be set using :symbols or "strings".
24
5
 
25
6
  == Install
26
7
 
27
8
  === Gem
28
9
 
29
- gem install symbolize
30
- config.gem "symbolize", :source => 'http://gemcutter.org'
10
+ gem install symbolize
31
11
 
32
12
 
33
- Rails 3+ Gemfile
13
+ === Mongoid
34
14
 
35
- gem "symbolize"
15
+ gem "symbolize", :require => "symbolize/mongoid"
36
16
 
37
17
 
38
- === Plugin:
18
+ === ActiveRecord
19
+
20
+ gem "symbolize", :require => "symbolize/active_record"
39
21
 
40
- ./script/plugin install git://github.com/nofxx/symbolize.git
41
22
 
42
- or in Rails3+
43
23
 
44
- rails plugin install ..
24
+ == About
45
25
 
26
+ Simply add "symbolize :attr_name" to your model class, and the specified
27
+ attribute will return symbol values and can be set using smbols (setting
28
+ string values will still work, which is important when using forms).
46
29
 
47
- == Rails 3 (beta)
30
+ On SQL-based DBs, an attribute to symbolize should be a string (varchar) column in the database.
48
31
 
49
- Specs pass with rails 3, but a scope :public == fail.
50
32
 
51
33
 
52
34
  == Usage
@@ -54,7 +36,14 @@ Specs pass with rails 3, but a scope :public == fail.
54
36
  Add "symbolize :attr_name" to your model class. You may also want to add
55
37
  validates_inclusion_of to restrict the possible values (just like an enum).
56
38
 
39
+ # ActiveRecord
57
40
  class User < ActiveRecord::Base
41
+
42
+ # Mongoid
43
+ class User
44
+ include Mongoid::Document
45
+ include Mongoid::Symbolize
46
+
58
47
  symbolize :gender, :in => [:female, :male], :scopes => true
59
48
  symbolize :so, :in => {
60
49
  :linux => "Linux",
@@ -174,6 +163,15 @@ As the name suggest, the symbol you choose as default will be set in new objects
174
163
  u = User.new(:name => 'ET', :gender => :unknown)
175
164
  u.save # => validation fails
176
165
 
166
+ == Rails Form Example
167
+
168
+ class Coffee
169
+ symbolize :genetic, :in => [:arabica, :robusta, :blend]
170
+ end
171
+
172
+ form_for(@coffee) do |f|
173
+ = f.label :genetic
174
+ = f.select :genetic, Coffee.get_genetic_values
177
175
 
178
176
  == Model Helpers
179
177
 
@@ -181,9 +179,6 @@ As the name suggest, the symbol you choose as default will be set in new objects
181
179
  You may call `Class.get_attr_values` anywhere to get a nice array.
182
180
  Works nice with dropdowns. Examples:
183
181
 
184
- class Coffee
185
- symbolize :genetic, :in => [:arabica, :robusta, :blend]
186
- end
187
182
 
188
183
  Somewhere on a view:
189
184
 
@@ -221,6 +216,27 @@ Somewhere on a view:
221
216
  </form>
222
217
 
223
218
 
219
+
220
+ === Plugin:
221
+
222
+ Try at your own risk.
223
+
224
+ rails plugin install git://github.com/nofxx/symbolize.git
225
+
226
+
227
+ == Rails 3.1 (beta)
228
+
229
+ Specs pass with rails 3, but a scope :public == fail.
230
+
231
+
232
+ == Specs
233
+
234
+ Run the adapter independently:
235
+
236
+ $ rspec spec/symbolize/mongoid_spec.rb
237
+ $ rspec spec/symbolize/active_record_spec.rb
238
+
239
+
224
240
  == Notes
225
241
 
226
242
  This fork:
data/Rakefile CHANGED
@@ -6,8 +6,8 @@ begin
6
6
  require 'jeweler'
7
7
  Jeweler::Tasks.new do |gem|
8
8
  gem.name = "symbolize"
9
- gem.summary = "ActiveRecord enums with i18n"
10
- gem.description = "ActiveRecord enums with i18n"
9
+ gem.summary = "Object enums with i18n in AR or Mongoid"
10
+ gem.description = "ActiveRecord/Mongoid enums with i18n"
11
11
  gem.email = "x@nofxx.com"
12
12
  gem.homepage = "http://github.com/nofxx/symbolize"
13
13
  gem.authors = ["Marcos Piccinini"]
@@ -39,7 +39,7 @@ end
39
39
  # rdoc.rdoc_files.include('README')
40
40
  # rdoc.rdoc_files.include('lib/**/*.rb')
41
41
  # end
42
- require 'rake/rdoctask'
42
+ require 'rdoc/task'
43
43
  Rake::RDocTask.new do |rdoc|
44
44
  if File.exist?('VERSION.yml')
45
45
  config = YAML.load(File.read('VERSION.yml'))
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.3.0
1
+ 4.0.1
@@ -0,0 +1,194 @@
1
+ module Symbolize
2
+ def self.included base
3
+ base.extend(ClassMethods)
4
+ end
5
+
6
+ # Symbolize ActiveRecord attributes. Add
7
+ # symbolize :attr_name
8
+ # to your model class, to make an attribute return symbols instead of
9
+ # string values. Setting such an attribute will accept symbols as well
10
+ # as strings. In the database, the symbolized attribute should have
11
+ # the column-type :string.
12
+ #
13
+ # Example:
14
+ # class User < ActiveRecord::Base
15
+ # symbolize :gender, :in => [:female, :male]
16
+ # symbolize :so, :in => {
17
+ # :linux => "Linux",
18
+ # :mac => "Mac OS X"
19
+ # }
20
+ # symbolize :gui, , :in => [:gnome, :kde, :xfce], :allow_blank => true
21
+ # symbolize :browser, :in => [:firefox, :opera], :i18n => false
22
+ # end
23
+ #
24
+ # It will automattically lookup for i18n:
25
+ #
26
+ # activerecord:
27
+ # attributes:
28
+ # user:
29
+ # enums:
30
+ # gender:
31
+ # female: Girl
32
+ # male: Boy
33
+ #
34
+ # You can skip i18n lookup with :i18n => false
35
+ # symbolize :gender, :in => [:female, :male], :i18n => false
36
+ #
37
+ # Its possible to use boolean fields also.
38
+ # symbolize :switch, :in => [true, false]
39
+ #
40
+ # ...
41
+ # switch:
42
+ # "true": On
43
+ # "false": Off
44
+ # "nil": Unknown
45
+ #
46
+ module ClassMethods
47
+ # Specifies that values of the given attributes should be returned
48
+ # as symbols. The table column should be created of type string.
49
+
50
+ def symbolize *attr_names
51
+ configuration = {}
52
+ configuration.update(attr_names.extract_options!)
53
+
54
+ enum = configuration[:in] || configuration[:within]
55
+ i18n = configuration.delete(:i18n).nil? && !enum.instance_of?(Hash) && enum ? true : configuration[:i18n]
56
+ scopes = configuration.delete :scopes
57
+ methods = configuration.delete :methods
58
+ capitalize = configuration.delete :capitalize
59
+ validation = configuration.delete(:validation) != false
60
+ default_option = configuration.delete :default
61
+
62
+ unless enum.nil?
63
+ # Little monkeypatching, <1.8 Hashes aren't ordered.
64
+ hsh = RUBY_VERSION > '1.9' || !defined?("ActiveSupport") ? Hash : ActiveSupport::OrderedHash
65
+
66
+ attr_names.each do |attr_name|
67
+ attr_name = attr_name.to_s
68
+ const = "#{attr_name}_values"
69
+ if enum.is_a?(Hash)
70
+ values = enum
71
+ else
72
+ values = hsh.new
73
+ enum.map do |val|
74
+ key = val.respond_to?(:to_sym) ? val.to_sym : val
75
+ values[key] = capitalize ? val.to_s.capitalize : val.to_s
76
+ end
77
+ end
78
+
79
+ # Get the values of :in
80
+ const_set const.upcase, values unless const_defined? const.upcase
81
+ ev = if i18n
82
+ # This one is a dropdown helper
83
+ code = "#{const.upcase}.map { |k,v| [I18n.translate(\"activerecord.attributes.\#{ActiveSupport::Inflector.underscore(self)}.enums.#{attr_name}.\#{k}\"), k] }" #.to_sym rescue nila
84
+ "def self.get_#{const}; #{code}; end;"
85
+ else
86
+ "def self.get_#{const}; #{const.upcase}.map(&:reverse); end"
87
+ end
88
+ class_eval(ev)
89
+
90
+ if methods
91
+ values.each do |value|
92
+ define_method("#{value[0]}?") do
93
+ self.send(attr_name) == value[0]
94
+ end
95
+ end
96
+ end
97
+
98
+ if scopes
99
+ scope_comm = lambda { |*args| ActiveRecord::VERSION::MAJOR >= 3 ? scope(*args) : named_scope(*args)}
100
+ values.each do |value|
101
+ if value[0].respond_to?(:to_sym)
102
+ scope_comm.call value[0].to_sym, :conditions => { attr_name => value[0].to_sym }
103
+ elsif ActiveRecord::VERSION::STRING <= "3.0"
104
+ if value[0] == true || value[0] == false
105
+ scope_comm.call "with_#{attr_name}".to_sym, :conditions => { attr_name => '1' }
106
+ scope_comm.call "without_#{attr_name}".to_sym, :conditions => { attr_name => '0' }
107
+
108
+ scope_comm.call attr_name.to_sym, :conditions => { attr_name => '1' }
109
+ scope_comm.call "not_#{attr_name}".to_sym, :conditions => { attr_name => '0' }
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
115
+
116
+ if validation
117
+ class_eval "validates_inclusion_of :#{attr_names.join(', :')}, #{configuration.inspect}"
118
+ end
119
+ end
120
+
121
+ attr_names.each do |attr_name|
122
+
123
+ if default_option
124
+ class_eval("def #{attr_name}; read_and_symbolize_attribute('#{attr_name}') || :#{default_option}; end")
125
+ class_eval("def #{attr_name}= (value); write_symbolized_attribute('#{attr_name}', value); end")
126
+ class_eval("def set_default_for_attr_#{attr_name}; self[:#{attr_name}] ||= :#{default_option}; end")
127
+ class_eval("before_save :set_default_for_attr_#{attr_name}")
128
+ else
129
+ class_eval("def #{attr_name}; read_and_symbolize_attribute('#{attr_name}'); end")
130
+ class_eval("def #{attr_name}= (value); write_symbolized_attribute('#{attr_name}', value); end")
131
+ end
132
+ if i18n
133
+ class_eval("def #{attr_name}_text; read_i18n_attribute('#{attr_name}'); end")
134
+ elsif enum
135
+ class_eval("def #{attr_name}_text; #{attr_name.to_s.upcase}_VALUES[#{attr_name}]; end")
136
+ else
137
+ class_eval("def #{attr_name}_text; #{attr_name}.to_s; end")
138
+ end
139
+ end
140
+ end
141
+ end
142
+
143
+ # String becomes symbol, booleans string and nil nil.
144
+ def symbolize_attribute attr
145
+ case attr
146
+ when String then attr.empty? ? nil : attr.to_sym
147
+ when Symbol, TrueClass, FalseClass, Numeric then attr
148
+ else nil
149
+ end
150
+ end
151
+
152
+ # Return an attribute's value as a symbol or nil
153
+ def read_and_symbolize_attribute attr_name
154
+ symbolize_attribute self[attr_name]
155
+ end
156
+
157
+ # Return an attribute's i18n
158
+ def read_i18n_attribute attr_name
159
+ attr = read_attribute(attr_name)
160
+ return nil if attr.nil?
161
+ I18n.translate("activerecord.attributes.#{ActiveSupport::Inflector.underscore(self.class)}.enums.#{attr_name}.#{attr}") #.to_sym rescue nila
162
+ end
163
+
164
+ # Write a symbolized value. Watch out for booleans.
165
+ def write_symbolized_attribute attr_name, value
166
+ val = { "true" => true, "false" => false }[value]
167
+ val = symbolize_attribute(value) if val.nil?
168
+
169
+ self[attr_name] = val #.to_s # rails 3.1 fix
170
+ end
171
+ end
172
+
173
+ # The Symbol class is extended by method quoted_id which returns a string.
174
+ # The idea behind this is, that symbols are converted to plain strings
175
+ # when being quoted by ActiveRecord::ConnectionAdapters::Quoting#quote.
176
+ # This makes it possible to work with symbolized attibutes in sql conditions.
177
+ # E.g. validates_uniqueness_of could not use :scope with a symbolized
178
+ # attribute, because AR quotes it to YAML:
179
+ # "... AND status = '--- :active\n'"
180
+ # Having support for quoted_id in Symbol, makes AR quoting symbols correctly:
181
+ # "... AND status = 'active'"
182
+ # NOTE: Normally quoted_id should be implemented as a singleton method
183
+ # only used on symbols returned by read_and_symbolize_attribute,
184
+ # but unfortunately this is not possible since Symbol is an immediate
185
+ # value and therefore does not support singleton methods.
186
+ # class Symbol
187
+ # def quoted_id
188
+ # # A symbol can contain almost every character (even a backslash or an
189
+ # # apostrophe), so make sure to properly quote the string value here.
190
+ # "'#{ActiveRecord::Base.connection.quote_string(self.to_s)}'"
191
+ # end
192
+ # end
193
+
194
+ ActiveRecord::Base.send(:include, Symbolize) if ActiveRecord::VERSION::MAJOR >= 3
@@ -0,0 +1,172 @@
1
+ module Mongoid
2
+ module Symbolize
3
+ def self.included base
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ # Symbolize Mongoid attributes. Add:
8
+ # symbolize :attr_name
9
+ # to your model class, to make an attribute return symbols instead of
10
+ # string values. Setting such an attribute will accept symbols as well
11
+ # as strings.
12
+ #
13
+ # There's no need for 'field :attr_name', symbolize will do it.
14
+ #
15
+ # Example:
16
+ # class User
17
+ # include Mongoid::Document
18
+ # symbolize :gender, :in => [:female, :male]
19
+ # symbolize :so, :in => {
20
+ # :linux => "Linux",
21
+ # :mac => "Mac OS X"
22
+ # }
23
+ # symbolize :gui, , :in => [:gnome, :kde, :xfce], :allow_blank => true
24
+ # symbolize :browser, :in => [:firefox, :opera], :i18n => false
25
+ # end
26
+ #
27
+ # It will automattically lookup for i18n:
28
+ #
29
+ # models:
30
+ # attributes:
31
+ # user:
32
+ # enums:
33
+ # gender:
34
+ # female: Girl
35
+ # male: Boy
36
+ #
37
+ # You can skip i18n lookup with :i18n => false
38
+ # symbolize :gender, :in => [:female, :male], :i18n => false
39
+ #
40
+ # Its possible to use boolean fields also.
41
+ # symbolize :switch, :in => [true, false]
42
+ #
43
+ # ...
44
+ # switch:
45
+ # "true": On
46
+ # "false": Off
47
+ # "nil": Unknown
48
+ #
49
+ module ClassMethods
50
+ # Specifies that values of the given attributes should be returned
51
+ # as symbols. The table column should be created of type string.
52
+
53
+ def symbolize *attr_names
54
+ configuration = {}
55
+ configuration.update(attr_names.extract_options!)
56
+
57
+ enum = configuration[:in] || configuration[:within]
58
+ i18n = configuration.delete(:i18n).nil? && !enum.instance_of?(Hash) && enum ? true : configuration[:i18n]
59
+ scopes = configuration.delete :scopes
60
+ methods = configuration.delete :methods
61
+ capitalize = configuration.delete :capitalize
62
+ validation = configuration.delete(:validation) != false
63
+ default_opt = configuration.delete :default
64
+
65
+ unless enum.nil?
66
+ # Little monkeypatching, <1.8 Hashes aren't ordered.
67
+ # hsh = RUBY_VERSION > '1.9' || !defined?("ActiveSupport") ? Hash : ActiveSupport::OrderedHash
68
+
69
+ attr_names.each do |attr_name|
70
+ attr_name = attr_name.to_s
71
+
72
+ # Builds Mongoid 'field :name, type: type, :default
73
+ type = ", type: Symbol"
74
+ default = ", default: :#{default_opt}" if default_opt
75
+ class_eval("field :#{attr_name} #{type} #{default}")
76
+
77
+ const = "#{attr_name}_values"
78
+ if enum.is_a?(Hash)
79
+ values = enum
80
+ else
81
+ values = {}
82
+ enum.map do |val|
83
+ key = val.respond_to?(:to_sym) ? val.to_sym : val
84
+ values[key] = capitalize ? val.to_s.capitalize : val.to_s
85
+ end
86
+ end
87
+
88
+ # Get the values of :in
89
+ const_set const.upcase, values unless const_defined? const.upcase
90
+ ev = if i18n
91
+ # This one is a dropdown helper
92
+ code = "#{const.upcase}.map { |k,v| [I18n.t(\"mongoid.attributes.\#{ActiveSupport::Inflector.underscore(self)}.enums.#{attr_name}.\#{k}\"), k] }" #.to_sym rescue nila
93
+ "def self.get_#{const}; #{code}; end;"
94
+ else
95
+ "def self.get_#{const}; #{const.upcase}.map(&:reverse); end"
96
+ end
97
+ class_eval(ev)
98
+
99
+ if methods
100
+ values.each do |value|
101
+ define_method("#{value[0]}?") do
102
+ self.send(attr_name) == value[0]
103
+ end
104
+ end
105
+ end
106
+
107
+ if scopes
108
+ scope_comm = lambda { |*args| scope(*args)}
109
+ values.each do |value|
110
+ if value[0].respond_to?(:to_sym)
111
+ scope_comm.call value[0].to_sym, :conditions => { attr_name => value[0].to_sym }
112
+ end
113
+ end
114
+ end
115
+
116
+ if validation
117
+ class_eval "validates_inclusion_of :#{attr_names.join(', :')}, #{configuration.inspect}"
118
+ end
119
+ end
120
+ end
121
+
122
+ attr_names.each do |attr_name|
123
+
124
+ # if default_option
125
+ # class_eval("def #{attr_name}; read_and_symbolize_attribute('#{attr_name}') || :#{default_option}; end")
126
+ # class_eval("def #{attr_name}= (value); write_symbolized_attribute('#{attr_name}', value); end")
127
+ # class_eval("def set_default_for_attr_#{attr_name}; self[:#{attr_name}] ||= :#{default_option}; end")
128
+ # class_eval("before_save :set_default_for_attr_#{attr_name}")
129
+ # else
130
+ # class_eval("def #{attr_name}; read_and_symbolize_attribute('#{attr_name}'); end")
131
+ # class_eval("def #{attr_name}= (value); write_symbolized_attribute('#{attr_name}', value); end")
132
+ # end
133
+ if i18n
134
+ class_eval("def #{attr_name}_text; read_i18n_attribute('#{attr_name}'); end")
135
+ elsif enum
136
+ class_eval("def #{attr_name}_text; #{attr_name.to_s.upcase}_VALUES[#{attr_name}]; end")
137
+ else
138
+ class_eval("def #{attr_name}_text; #{attr_name}.to_s; end")
139
+ end
140
+ end
141
+ end
142
+ end
143
+
144
+ # String becomes symbol, booleans string and nil nil.
145
+ # def symbolize_attribute attr
146
+ # case attr
147
+ # when String then attr.empty? ? nil : attr.to_sym
148
+ # when Symbol, TrueClass, FalseClass, Numeric then attr
149
+ # else nil
150
+ # end
151
+ # end
152
+
153
+ # # Return an attribute's value as a symbol or nil
154
+ # def read_and_symbolize_attribute attr_name
155
+ # symbolize_attribute self[attr_name]
156
+ # end
157
+
158
+ # Return an attribute's i18n
159
+ def read_i18n_attribute attr_name
160
+ return nil unless attr = read_attribute(attr_name)
161
+ I18n.translate("activerecord.attributes.#{ActiveSupport::Inflector.underscore(self.class)}.enums.#{attr_name}.#{attr}") #.to_sym rescue nila
162
+ end
163
+
164
+ # # Write a symbolized value. Watch out for booleans.
165
+ # def write_symbolized_attribute attr_name, value
166
+ # val = { "true" => true, "false" => false }[value]
167
+ # val = symbolize_attribute(value) if val.nil?
168
+
169
+ # self[attr_name] = val #.to_s # rails 3.1 fix
170
+ # end
171
+ end
172
+ end
@@ -1,14 +1,15 @@
1
1
  # Rails 3 initialization
2
2
  module Symbolize
3
- if defined? Rails::Railtie
4
- require 'rails'
5
- class Railtie < Rails::Railtie
6
- initializer 'symbolize.insert_into_active_record' do
7
- ActiveSupport.on_load :active_record do
8
- ActiveRecord::Base.extend(Symbolize::ClassMethods)
9
- end
10
- end
11
- end
12
- end
3
+ # if defined? Rails::Railtie
4
+ # require 'rails'
5
+ # class Railtie < Rails::Railtie
6
+ # initializer 'symbolize.insert_into_active_record' do
7
+ # ActiveSupport.on_load :active_record do
8
+ # ActiveRecord::Base.extend(Symbolize::ClassMethods)
9
+ # end
10
+ # end
11
+ # end
12
+ # end
13
13
  end
14
14
 
15
+