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.
- data/lib/active_record_encoding.rb +108 -37
- 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
|
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
|
31
|
-
#
|
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
|
-
|
68
|
-
|
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
|
-
|
82
|
-
|
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
|
-
|
97
|
-
|
98
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
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
|
-
|
142
|
-
value = value.encode(
|
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
|
-
|
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 :
|
149
|
-
alias_method :
|
219
|
+
alias_method :pre_encoding_aware_read_attribute, :read_attribute
|
220
|
+
alias_method :read_attribute, :encoding_aware_read_attribute
|
150
221
|
end
|