cosine-active_record_encoding 0.9.1 → 0.9.2

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.
Files changed (2) hide show
  1. data/lib/active_record_encoding.rb +108 -37
  2. metadata +1 -1
@@ -6,7 +6,12 @@
6
6
 
7
7
  #
8
8
  # ActiveRecordEncoding — Module to make ActiveRecord aware of Unicode
9
- # encoding issues.
9
+ # encoding issues on Ruby 1.9. This software is not supported on Ruby
10
+ # 1.8 at all, and never will be. It should be used only if the
11
+ # underlying database does not or cannot properly handle the encoding of
12
+ # data that is returned as "ASCII-8BIT" encoded data. Most databases
13
+ # can properly encode data, so your first assumption should be that you
14
+ # do not need this software unless you really know you need it.
10
15
  #
11
16
  # ActiveRecordEncoding keeps two variables on the default encoding to
12
17
  # use when accessing the database.
@@ -14,6 +19,10 @@
14
19
  # ActiveRecordEncoding.external_encoding = 'ISO-8859-1'
15
20
  # ActiveRecordEncoding.internal_encoding = 'UTF-8'
16
21
  #
22
+ # Deprecation Notice: ActiveRecordEncoding.external_encoding will be
23
+ # discontinued in favor of explicitly setting encodings for particular
24
+ # tables and columns in a future version.
25
+ #
17
26
  # If the external_encoding is not explicitly set then no conversions
18
27
  # will be done. The internal_encoding value defaults to
19
28
  # Encoding.default_internal if not explicitly set.
@@ -21,16 +30,15 @@
21
30
  # The internal_encoding value is the encoding of the Strings that are
22
31
  # returned by ActiveRecord from String-based columns. The
23
32
  # external_encoding value tells ActiveRecord how the database is
24
- # encoding the data. A conversion is done if necessary.
33
+ # actually encoding the data that is being returned as "ASCII-8BIT".
34
+ # A conversion is done if necessary.
25
35
  #
26
36
  # When data is being saved back to the database, the internal_encoding
27
37
  # value is ignored and the encoding of the input is used to determine
28
38
  # how to encode the data in the external_encoding.
29
39
  #
30
- # Encodings may also be defined on a table-by-table basis in the model
31
- # definition. A future version of ActiveRecordEncoding may support
32
- # setting the encoding on a column-by-column basis, but that is not
33
- # currently possible.
40
+ # Encodings may also be defined on a table-by-table basis or
41
+ # a column-by-column basis in the model definition.
34
42
  #
35
43
  module ActiveRecordEncoding
36
44
 
@@ -54,32 +62,64 @@ end
54
62
 
55
63
  module ActiveRecordEncoding::ActiveRecordExtensionClassMethods
56
64
 
65
+ def active_record_encodings
66
+ @active_record_encodings ||= Hash.new { |h, k| h[k] = Hash.new }
67
+ end
68
+
57
69
  #
58
70
  # Set the external_encoding value for this model class.
59
71
  #
60
72
  # class User < ActiveRecord::Base
61
- # external_encoding 'ISO-8859-1'
73
+ # external_encoding 'ISO-8859-1' # affect all binary columns
62
74
  # end
63
75
  #
64
76
  # When data is retrieved from the database, it will be assumed it is
65
77
  # encoded in the given format.
66
78
  #
67
- def external_encoding (new_encoding)
68
- @active_record_external_encoding = new_encoding
79
+ # This may also be called with the :for option pointing to one or more
80
+ # specific columns that this call applies to:
81
+ #
82
+ # class User < ActiveRecord::Base
83
+ # external_encoding 'ISO-8859-1', :for => :comment
84
+ # external_encoding 'ISO-8859-1', :for => [:first_name, :last_name]
85
+ # end
86
+ #
87
+ def external_encoding (new_encoding, options = {})
88
+ if attr_names = options[:for]
89
+ [*attr_names].each do |attr_name|
90
+ active_record_encodings[attr_name.to_s][:ext] = new_encoding
91
+ end
92
+ else
93
+ @active_record_external_encoding = new_encoding
94
+ end
69
95
  end
70
96
 
71
97
  #
72
98
  # Set the internal_encoding value for this model class.
73
99
  #
74
100
  # class User < ActiveRecord::Base
75
- # internal_encoding 'UTF-8'
101
+ # internal_encoding 'UTF-8' # affect all binary columns
76
102
  # end
77
103
  #
78
104
  # When String objects are returned to the user as a result of an
79
105
  # ActiveRecord database lookup, they will be in the given format.
80
106
  #
81
- def internal_encoding (new_encoding)
82
- @active_record_internal_encoding = new_encoding
107
+ # This may also be called with the :for option pointing to one or more
108
+ # specific columns that this call applies to:
109
+ #
110
+ # class User < ActiveRecord::Base
111
+ # internal_encoding 'ISO-8859-1', :for => :comment
112
+ # internal_encoding 'ISO-8859-1', :for => [:first_name, :last_name]
113
+ # end
114
+ #
115
+ def internal_encoding (new_encoding, options = {})
116
+ if attr_names = options[:for]
117
+ [*attr_names].each do |attr_name|
118
+ active_record_encodings[attr_name.to_s][:int] = new_encoding
119
+ end
120
+ else
121
+ @active_record_internal_encoding = new_encoding
122
+ end
83
123
  end
84
124
 
85
125
  #
@@ -87,24 +127,41 @@ module ActiveRecordEncoding::ActiveRecordExtensionClassMethods
87
127
  # this model class.
88
128
  #
89
129
  # class User < ActiveRecord::Base
90
- # encoding 'UTF-8'
130
+ # encoding 'UTF-8' # affect all binary columns
91
131
  # end
92
132
  #
93
133
  # When data is retrived from the database, it will be assumed it is
94
134
  # encoded in the given format and returned in the same format.
95
135
  #
96
- def encoding (new_encoding)
97
- @active_record_external_encoding = new_encoding
98
- @active_record_internal_encoding = new_encoding
136
+ # This may also be called with the :for option pointing to one or more
137
+ # specific columns that this call applies to:
138
+ #
139
+ # class User < ActiveRecord::Base
140
+ # encoding 'ISO-8859-1', :for => :comment
141
+ # encoding 'ISO-8859-1', :for => [:first_name, :last_name]
142
+ # end
143
+ #
144
+ def encoding (new_encoding, options = {})
145
+ if attr_names = options[:for]
146
+ [*attr_names].each do |attr_name|
147
+ active_record_encodings[attr_name.to_s] =
148
+ { :ext => new_encoding, :int => new_encoding }
149
+ end
150
+ else
151
+ @active_record_external_encoding = new_encoding
152
+ @active_record_internal_encoding = new_encoding
153
+ end
99
154
  end
100
155
 
101
- def active_record_external_encoding #:nodoc:
102
- @active_record_external_encoding ||
156
+ def active_record_external_encoding (attr_name = nil) #:nodoc:
157
+ active_record_encodings[attr_name][:ext] ||
158
+ @active_record_external_encoding ||
103
159
  ActiveRecordEncoding.external_encoding
104
160
  end
105
161
 
106
- def active_record_internal_encoding #:nodoc:
107
- @active_record_internal_encoding ||
162
+ def active_record_internal_encoding (attr_name = nil) #:nodoc:
163
+ active_record_encodings[attr_name][:int] ||
164
+ @active_record_internal_encoding ||
108
165
  ActiveRecordEncoding.internal_encoding ||
109
166
  Encoding.default_internal ||
110
167
  Encoding.default_external ||
@@ -116,35 +173,49 @@ end
116
173
  class ActiveRecord::Base #:nodoc:
117
174
  extend ActiveRecordEncoding::ActiveRecordExtensionClassMethods
118
175
 
119
-
120
- def encoding_aware_read_attribute (attr_name)
176
+ # Normal replacement method for read_attribute.
177
+ def pure_encoding_aware_read_attribute (attr_name) #:nodoc:
121
178
  value = pre_encoding_aware_read_attribute(attr_name)
122
179
 
123
- if value.respond_to? :encoding and value.encoding.to_s.eql?('ASCII-8BIT')
124
- external_encoding = self.class.active_record_external_encoding
125
-
126
- if external_encoding = self.class.active_record_external_encoding
127
- internal_encoding = self.class.active_record_internal_encoding
128
- value.force_encoding(external_encoding).encode!(internal_encoding)
129
- end
180
+ if value.respond_to? :encoding and
181
+ value.encoding.to_s.eql?('ASCII-8BIT') and
182
+ ext_encoding = self.class.active_record_external_encoding(attr_name) \
183
+ then
184
+ int_encoding = self.class.active_record_internal_encoding(attr_name)
185
+ value.force_encoding(ext_encoding).encode!(int_encoding)
130
186
  end
131
187
 
132
188
  value
133
189
  end
190
+ private :pure_encoding_aware_read_attribute
134
191
 
135
- alias_method :pre_encoding_aware_read_attribute, :read_attribute
136
- alias_method :read_attribute, :encoding_aware_read_attribute
137
192
 
193
+ # Replacement method for read_attribute when Rails is preparing data
194
+ # for write.
195
+ def encoding_aware_read_attribute_for_write (attr_name) #:nodoc:
196
+ value = pure_encoding_aware_read_attribute(attr_name)
138
197
 
139
- def encoding_aware_write_attribute (attr_name, value)
140
198
  if value.respond_to? :encoding and
141
- external_encoding = self.class.active_record_external_encoding
142
- value = value.encode(external_encoding)
199
+ ext_encoding = self.class.active_record_external_encoding(attr_name)
200
+ value = value.encode(ext_encoding).force_encoding('ASCII-8BIT')
143
201
  end
144
202
 
145
- pre_encoding_aware_write_attribute(attr_name, value)
203
+ value
204
+ end
205
+ private :encoding_aware_read_attribute_for_write
206
+
207
+
208
+ def encoding_aware_read_attribute (attr_name) #:nodoc:
209
+ # We need to behave differently if called from
210
+ # #attributes_with_quotes because that is how Rails knows what value
211
+ # to write out. Doing it this way is an unfortunate kludge.
212
+ rc = if caller.grep(/`attributes_with_quotes'$/).empty?
213
+ pure_encoding_aware_read_attribute(attr_name)
214
+ else
215
+ encoding_aware_read_attribute_for_write(attr_name)
216
+ end
146
217
  end
147
218
 
148
- alias_method :pre_encoding_aware_write_attribute, :write_attribute
149
- alias_method :write_attribute, :encoding_aware_write_attribute
219
+ alias_method :pre_encoding_aware_read_attribute, :read_attribute
220
+ alias_method :read_attribute, :encoding_aware_read_attribute
150
221
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cosine-active_record_encoding
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 0.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael H. Buselli