activesupport 3.0.0.rc → 3.0.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- data/CHANGELOG +42 -37
- data/lib/active_support/base64.rb +3 -3
- data/lib/active_support/benchmarkable.rb +3 -3
- data/lib/active_support/cache.rb +46 -56
- data/lib/active_support/cache/mem_cache_store.rb +3 -4
- data/lib/active_support/cache/memory_store.rb +5 -5
- data/lib/active_support/cache/strategy/local_cache.rb +5 -5
- data/lib/active_support/callbacks.rb +13 -3
- data/lib/active_support/concern.rb +35 -0
- data/lib/active_support/configurable.rb +2 -2
- data/lib/active_support/core_ext/array/conversions.rb +6 -6
- data/lib/active_support/core_ext/array/random_access.rb +4 -4
- data/lib/active_support/core_ext/array/uniq_by.rb +1 -1
- data/lib/active_support/core_ext/array/wrap.rb +30 -4
- data/lib/active_support/core_ext/class/attribute.rb +27 -4
- data/lib/active_support/core_ext/class/attribute_accessors.rb +16 -0
- data/lib/active_support/core_ext/class/inheritable_attributes.rb +25 -3
- data/lib/active_support/core_ext/date/calculations.rb +15 -15
- data/lib/active_support/core_ext/date_time/conversions.rb +6 -6
- data/lib/active_support/core_ext/date_time/zones.rb +1 -1
- data/lib/active_support/core_ext/enumerable.rb +6 -5
- data/lib/active_support/core_ext/hash/conversions.rb +11 -11
- data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -3
- data/lib/active_support/core_ext/integer/time.rb +2 -2
- data/lib/active_support/core_ext/kernel/reporting.rb +1 -1
- data/lib/active_support/core_ext/module/anonymous.rb +1 -1
- data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +2 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +1 -1
- data/lib/active_support/core_ext/module/remove_method.rb +1 -1
- data/lib/active_support/core_ext/module/synchronization.rb +2 -2
- data/lib/active_support/core_ext/numeric/time.rb +9 -9
- data/lib/active_support/core_ext/object.rb +1 -0
- data/lib/active_support/core_ext/object/blank.rb +1 -1
- data/lib/active_support/core_ext/object/instance_variables.rb +5 -5
- data/lib/active_support/core_ext/object/returning.rb +43 -0
- data/lib/active_support/core_ext/range/conversions.rb +1 -1
- data/lib/active_support/core_ext/string/access.rb +7 -7
- data/lib/active_support/core_ext/string/inflections.rb +8 -6
- data/lib/active_support/core_ext/string/multibyte.rb +5 -5
- data/lib/active_support/core_ext/time/calculations.rb +2 -2
- data/lib/active_support/core_ext/time/conversions.rb +1 -1
- data/lib/active_support/core_ext/time/zones.rb +3 -3
- data/lib/active_support/dependencies.rb +56 -38
- data/lib/active_support/duration.rb +1 -1
- data/lib/active_support/hash_with_indifferent_access.rb +9 -3
- data/lib/active_support/i18n_railtie.rb +1 -1
- data/lib/active_support/lazy_load_hooks.rb +20 -1
- data/lib/active_support/locale/en.yml +3 -3
- data/lib/active_support/log_subscriber.rb +32 -33
- data/lib/active_support/log_subscriber/test_helper.rb +1 -1
- data/lib/active_support/message_encryptor.rb +17 -17
- data/lib/active_support/message_verifier.rb +7 -7
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/multibyte/chars.rb +37 -36
- data/lib/active_support/multibyte/unicode.rb +4 -4
- data/lib/active_support/notifications.rb +3 -3
- data/lib/active_support/secure_random.rb +13 -13
- data/lib/active_support/testing/assertions.rb +8 -6
- data/lib/active_support/testing/declarative.rb +4 -4
- data/lib/active_support/testing/isolation.rb +1 -1
- data/lib/active_support/testing/pending.rb +3 -3
- data/lib/active_support/testing/performance.rb +9 -5
- data/lib/active_support/time_with_zone.rb +2 -2
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/nokogiri.rb +6 -1
- data/lib/active_support/xml_mini/nokogirisax.rb +7 -2
- data/lib/active_support/xml_mini/rexml.rb +1 -1
- metadata +5 -4
@@ -2,9 +2,9 @@ require 'openssl'
|
|
2
2
|
require 'active_support/base64'
|
3
3
|
|
4
4
|
module ActiveSupport
|
5
|
-
# MessageEncryptor is a simple way to encrypt values which get stored somewhere
|
5
|
+
# MessageEncryptor is a simple way to encrypt values which get stored somewhere
|
6
6
|
# you don't trust.
|
7
|
-
#
|
7
|
+
#
|
8
8
|
# The cipher text and initialization vector are base64 encoded and returned to you.
|
9
9
|
#
|
10
10
|
# This can be used in situations similar to the MessageVerifier, but where you don't
|
@@ -17,53 +17,53 @@ module ActiveSupport
|
|
17
17
|
@secret = secret
|
18
18
|
@cipher = cipher
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
def encrypt(value)
|
22
22
|
cipher = new_cipher
|
23
23
|
# Rely on OpenSSL for the initialization vector
|
24
24
|
iv = cipher.random_iv
|
25
|
-
|
26
|
-
cipher.encrypt
|
25
|
+
|
26
|
+
cipher.encrypt
|
27
27
|
cipher.key = @secret
|
28
28
|
cipher.iv = iv
|
29
|
-
|
30
|
-
encrypted_data = cipher.update(Marshal.dump(value))
|
29
|
+
|
30
|
+
encrypted_data = cipher.update(Marshal.dump(value))
|
31
31
|
encrypted_data << cipher.final
|
32
32
|
|
33
33
|
[encrypted_data, iv].map {|v| ActiveSupport::Base64.encode64s(v)}.join("--")
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
def decrypt(encrypted_message)
|
37
37
|
cipher = new_cipher
|
38
38
|
encrypted_data, iv = encrypted_message.split("--").map {|v| ActiveSupport::Base64.decode64(v)}
|
39
|
-
|
39
|
+
|
40
40
|
cipher.decrypt
|
41
41
|
cipher.key = @secret
|
42
42
|
cipher.iv = iv
|
43
43
|
|
44
44
|
decrypted_data = cipher.update(encrypted_data)
|
45
45
|
decrypted_data << cipher.final
|
46
|
-
|
46
|
+
|
47
47
|
Marshal.load(decrypted_data)
|
48
48
|
rescue OpenSSLCipherError, TypeError
|
49
49
|
raise InvalidMessage
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
def encrypt_and_sign(value)
|
53
53
|
verifier.generate(encrypt(value))
|
54
54
|
end
|
55
|
-
|
55
|
+
|
56
56
|
def decrypt_and_verify(value)
|
57
57
|
decrypt(verifier.verify(value))
|
58
58
|
end
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
private
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
private
|
63
63
|
def new_cipher
|
64
64
|
OpenSSL::Cipher::Cipher.new(@cipher)
|
65
65
|
end
|
66
|
-
|
66
|
+
|
67
67
|
def verifier
|
68
68
|
MessageVerifier.new(@secret)
|
69
69
|
end
|
@@ -4,28 +4,28 @@ require 'active_support/core_ext/object/blank'
|
|
4
4
|
module ActiveSupport
|
5
5
|
# MessageVerifier makes it easy to generate and verify messages which are signed
|
6
6
|
# to prevent tampering.
|
7
|
-
#
|
7
|
+
#
|
8
8
|
# This is useful for cases like remember-me tokens and auto-unsubscribe links where the
|
9
9
|
# session store isn't suitable or available.
|
10
10
|
#
|
11
11
|
# Remember Me:
|
12
12
|
# cookies[:remember_me] = @verifier.generate([@user.id, 2.weeks.from_now])
|
13
|
-
#
|
13
|
+
#
|
14
14
|
# In the authentication filter:
|
15
15
|
#
|
16
16
|
# id, time = @verifier.verify(cookies[:remember_me])
|
17
17
|
# if time < Time.now
|
18
18
|
# self.current_user = User.find(id)
|
19
19
|
# end
|
20
|
-
#
|
20
|
+
#
|
21
21
|
class MessageVerifier
|
22
22
|
class InvalidSignature < StandardError; end
|
23
|
-
|
23
|
+
|
24
24
|
def initialize(secret, digest = 'SHA1')
|
25
25
|
@secret = secret
|
26
26
|
@digest = digest
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
def verify(signed_message)
|
30
30
|
raise InvalidSignature if signed_message.blank?
|
31
31
|
|
@@ -36,12 +36,12 @@ module ActiveSupport
|
|
36
36
|
raise InvalidSignature
|
37
37
|
end
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
def generate(value)
|
41
41
|
data = ActiveSupport::Base64.encode64s(Marshal.dump(value))
|
42
42
|
"#{data}--#{generate_digest(data)}"
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
45
|
private
|
46
46
|
# constant-time comparison algorithm to prevent timing attacks
|
47
47
|
def secure_compare(a, b)
|
@@ -6,7 +6,7 @@ module ActiveSupport #:nodoc:
|
|
6
6
|
autoload :EncodingError, 'active_support/multibyte/exceptions'
|
7
7
|
autoload :Chars, 'active_support/multibyte/chars'
|
8
8
|
autoload :Unicode, 'active_support/multibyte/unicode'
|
9
|
-
|
9
|
+
|
10
10
|
# The proxy class returned when calling mb_chars. You can use this accessor to configure your own proxy
|
11
11
|
# class so you can support other encodings. See the ActiveSupport::Multibyte::Chars implementation for
|
12
12
|
# an example how to do this.
|
@@ -11,7 +11,7 @@ module ActiveSupport #:nodoc:
|
|
11
11
|
# String methods are proxied through the Chars object, and can be accessed through the +mb_chars+ method. Methods
|
12
12
|
# which would normally return a String object now return a Chars object so methods can be chained.
|
13
13
|
#
|
14
|
-
# "The Perfect String ".mb_chars.downcase.strip.normalize
|
14
|
+
# "The Perfect String ".mb_chars.downcase.strip.normalize # => "the perfect string"
|
15
15
|
#
|
16
16
|
# Chars objects are perfectly interchangeable with String objects as long as no explicit class checks are made.
|
17
17
|
# If certain methods do explicitly check the class, call +to_s+ before you pass chars objects to them.
|
@@ -83,12 +83,13 @@ module ActiveSupport #:nodoc:
|
|
83
83
|
|
84
84
|
include Comparable
|
85
85
|
|
86
|
-
# Returns
|
87
|
-
# equal or after the object on the right side of the operation. It accepts any object
|
88
|
-
#
|
86
|
+
# Returns -1, 0, or 1, depending on whether the Chars object is to be sorted before,
|
87
|
+
# equal or after the object on the right side of the operation. It accepts any object
|
88
|
+
# that implements +to_s+:
|
89
89
|
#
|
90
|
-
#
|
91
|
-
#
|
90
|
+
# 'é'.mb_chars <=> 'ü'.mb_chars # => -1
|
91
|
+
#
|
92
|
+
# See <tt>String#<=></tt> for more details.
|
92
93
|
def <=>(other)
|
93
94
|
@wrapped_string <=> other.to_s
|
94
95
|
end
|
@@ -103,7 +104,7 @@ module ActiveSupport #:nodoc:
|
|
103
104
|
# Returns a new Chars object containing the _other_ object concatenated to the string.
|
104
105
|
#
|
105
106
|
# Example:
|
106
|
-
# ('Café'.mb_chars + ' périferôl').to_s
|
107
|
+
# ('Café'.mb_chars + ' périferôl').to_s # => "Café périferôl"
|
107
108
|
def +(other)
|
108
109
|
chars(@wrapped_string + other)
|
109
110
|
end
|
@@ -111,7 +112,7 @@ module ActiveSupport #:nodoc:
|
|
111
112
|
# Like <tt>String#=~</tt> only it returns the character offset (in codepoints) instead of the byte offset.
|
112
113
|
#
|
113
114
|
# Example:
|
114
|
-
# 'Café périferôl'.mb_chars =~ /ô/
|
115
|
+
# 'Café périferôl'.mb_chars =~ /ô/ # => 12
|
115
116
|
def =~(other)
|
116
117
|
translate_offset(@wrapped_string =~ other)
|
117
118
|
end
|
@@ -119,7 +120,7 @@ module ActiveSupport #:nodoc:
|
|
119
120
|
# Inserts the passed string at specified codepoint offsets.
|
120
121
|
#
|
121
122
|
# Example:
|
122
|
-
# 'Café'.mb_chars.insert(4, ' périferôl').to_s
|
123
|
+
# 'Café'.mb_chars.insert(4, ' périferôl').to_s # => "Café périferôl"
|
123
124
|
def insert(offset, fragment)
|
124
125
|
unpacked = Unicode.u_unpack(@wrapped_string)
|
125
126
|
unless offset > unpacked.length
|
@@ -135,7 +136,7 @@ module ActiveSupport #:nodoc:
|
|
135
136
|
# Returns +true+ if contained string contains _other_. Returns +false+ otherwise.
|
136
137
|
#
|
137
138
|
# Example:
|
138
|
-
# 'Café'.mb_chars.include?('é')
|
139
|
+
# 'Café'.mb_chars.include?('é') # => true
|
139
140
|
def include?(other)
|
140
141
|
# We have to redefine this method because Enumerable defines it.
|
141
142
|
@wrapped_string.include?(other)
|
@@ -144,8 +145,8 @@ module ActiveSupport #:nodoc:
|
|
144
145
|
# Returns the position _needle_ in the string, counting in codepoints. Returns +nil+ if _needle_ isn't found.
|
145
146
|
#
|
146
147
|
# Example:
|
147
|
-
# 'Café périferôl'.mb_chars.index('ô')
|
148
|
-
# 'Café périferôl'.mb_chars.index(/\w/u)
|
148
|
+
# 'Café périferôl'.mb_chars.index('ô') # => 12
|
149
|
+
# 'Café périferôl'.mb_chars.index(/\w/u) # => 0
|
149
150
|
def index(needle, offset=0)
|
150
151
|
wrapped_offset = first(offset).wrapped_string.length
|
151
152
|
index = @wrapped_string.index(needle, wrapped_offset)
|
@@ -157,8 +158,8 @@ module ActiveSupport #:nodoc:
|
|
157
158
|
# string. Returns +nil+ if _needle_ isn't found.
|
158
159
|
#
|
159
160
|
# Example:
|
160
|
-
# 'Café périferôl'.mb_chars.rindex('é')
|
161
|
-
# 'Café périferôl'.mb_chars.rindex(/\w/u)
|
161
|
+
# 'Café périferôl'.mb_chars.rindex('é') # => 6
|
162
|
+
# 'Café périferôl'.mb_chars.rindex(/\w/u) # => 13
|
162
163
|
def rindex(needle, offset=nil)
|
163
164
|
offset ||= length
|
164
165
|
wrapped_offset = first(offset).wrapped_string.length
|
@@ -190,7 +191,7 @@ module ActiveSupport #:nodoc:
|
|
190
191
|
# Returns the codepoint of the first character in the string.
|
191
192
|
#
|
192
193
|
# Example:
|
193
|
-
# 'こんにちは'.mb_chars.ord
|
194
|
+
# 'こんにちは'.mb_chars.ord # => 12371
|
194
195
|
def ord
|
195
196
|
Unicode.u_unpack(@wrapped_string)[0]
|
196
197
|
end
|
@@ -200,10 +201,10 @@ module ActiveSupport #:nodoc:
|
|
200
201
|
# Example:
|
201
202
|
#
|
202
203
|
# "¾ cup".mb_chars.rjust(8).to_s
|
203
|
-
#
|
204
|
+
# # => " ¾ cup"
|
204
205
|
#
|
205
206
|
# "¾ cup".mb_chars.rjust(8, " ").to_s # Use non-breaking whitespace
|
206
|
-
#
|
207
|
+
# # => " ¾ cup"
|
207
208
|
def rjust(integer, padstr=' ')
|
208
209
|
justify(integer, :right, padstr)
|
209
210
|
end
|
@@ -213,10 +214,10 @@ module ActiveSupport #:nodoc:
|
|
213
214
|
# Example:
|
214
215
|
#
|
215
216
|
# "¾ cup".mb_chars.rjust(8).to_s
|
216
|
-
#
|
217
|
+
# # => "¾ cup "
|
217
218
|
#
|
218
219
|
# "¾ cup".mb_chars.rjust(8, " ").to_s # Use non-breaking whitespace
|
219
|
-
#
|
220
|
+
# # => "¾ cup "
|
220
221
|
def ljust(integer, padstr=' ')
|
221
222
|
justify(integer, :left, padstr)
|
222
223
|
end
|
@@ -226,10 +227,10 @@ module ActiveSupport #:nodoc:
|
|
226
227
|
# Example:
|
227
228
|
#
|
228
229
|
# "¾ cup".mb_chars.center(8).to_s
|
229
|
-
#
|
230
|
+
# # => " ¾ cup "
|
230
231
|
#
|
231
232
|
# "¾ cup".mb_chars.center(8, " ").to_s # Use non-breaking whitespace
|
232
|
-
#
|
233
|
+
# # => " ¾ cup "
|
233
234
|
def center(integer, padstr=' ')
|
234
235
|
justify(integer, :center, padstr)
|
235
236
|
end
|
@@ -244,7 +245,7 @@ module ActiveSupport #:nodoc:
|
|
244
245
|
# instances instead of String. This makes chaining methods easier.
|
245
246
|
#
|
246
247
|
# Example:
|
247
|
-
# 'Café périferôl'.mb_chars.split(/é/).map { |part| part.upcase.to_s }
|
248
|
+
# 'Café périferôl'.mb_chars.split(/é/).map { |part| part.upcase.to_s } # => ["CAF", " P", "RIFERÔL"]
|
248
249
|
def split(*args)
|
249
250
|
@wrapped_string.split(*args).map { |i| i.mb_chars }
|
250
251
|
end
|
@@ -256,12 +257,12 @@ module ActiveSupport #:nodoc:
|
|
256
257
|
# s = "Müller"
|
257
258
|
# s.mb_chars[2] = "e" # Replace character with offset 2
|
258
259
|
# s
|
259
|
-
#
|
260
|
+
# # => "Müeler"
|
260
261
|
#
|
261
262
|
# s = "Müller"
|
262
263
|
# s.mb_chars[1, 2] = "ö" # Replace 2 characters at character offset 1
|
263
264
|
# s
|
264
|
-
#
|
265
|
+
# # => "Möler"
|
265
266
|
def []=(*args)
|
266
267
|
replace_by = args.pop
|
267
268
|
# Indexed replace with regular expressions already works
|
@@ -292,7 +293,7 @@ module ActiveSupport #:nodoc:
|
|
292
293
|
# Reverses all characters in the string.
|
293
294
|
#
|
294
295
|
# Example:
|
295
|
-
# 'Café'.mb_chars.reverse.to_s
|
296
|
+
# 'Café'.mb_chars.reverse.to_s # => 'éfaC'
|
296
297
|
def reverse
|
297
298
|
chars(Unicode.g_unpack(@wrapped_string).reverse.flatten.pack('U*'))
|
298
299
|
end
|
@@ -301,7 +302,7 @@ module ActiveSupport #:nodoc:
|
|
301
302
|
# character.
|
302
303
|
#
|
303
304
|
# Example:
|
304
|
-
# 'こんにちは'.mb_chars.slice(2..3).to_s
|
305
|
+
# 'こんにちは'.mb_chars.slice(2..3).to_s # => "にち"
|
305
306
|
def slice(*args)
|
306
307
|
if args.size > 2
|
307
308
|
raise ArgumentError, "wrong number of arguments (#{args.size} for 1)" # Do as if we were native
|
@@ -330,7 +331,7 @@ module ActiveSupport #:nodoc:
|
|
330
331
|
#
|
331
332
|
# Example:
|
332
333
|
# s = 'こんにちは'
|
333
|
-
# s.mb_chars.limit(7)
|
334
|
+
# s.mb_chars.limit(7) # => "こに"
|
334
335
|
def limit(limit)
|
335
336
|
slice(0...translate_offset(limit))
|
336
337
|
end
|
@@ -338,7 +339,7 @@ module ActiveSupport #:nodoc:
|
|
338
339
|
# Convert characters in the string to uppercase.
|
339
340
|
#
|
340
341
|
# Example:
|
341
|
-
# 'Laurent, où sont les tests ?'.mb_chars.upcase.to_s
|
342
|
+
# 'Laurent, où sont les tests ?'.mb_chars.upcase.to_s # => "LAURENT, OÙ SONT LES TESTS ?"
|
342
343
|
def upcase
|
343
344
|
chars(Unicode.apply_mapping @wrapped_string, :uppercase_mapping)
|
344
345
|
end
|
@@ -346,7 +347,7 @@ module ActiveSupport #:nodoc:
|
|
346
347
|
# Convert characters in the string to lowercase.
|
347
348
|
#
|
348
349
|
# Example:
|
349
|
-
# 'VĚDA A VÝZKUM'.mb_chars.downcase.to_s
|
350
|
+
# 'VĚDA A VÝZKUM'.mb_chars.downcase.to_s # => "věda a výzkum"
|
350
351
|
def downcase
|
351
352
|
chars(Unicode.apply_mapping @wrapped_string, :lowercase_mapping)
|
352
353
|
end
|
@@ -354,7 +355,7 @@ module ActiveSupport #:nodoc:
|
|
354
355
|
# Converts the first character to uppercase and the remainder to lowercase.
|
355
356
|
#
|
356
357
|
# Example:
|
357
|
-
# 'über'.mb_chars.capitalize.to_s
|
358
|
+
# 'über'.mb_chars.capitalize.to_s # => "Über"
|
358
359
|
def capitalize
|
359
360
|
(slice(0) || chars('')).upcase + (slice(1..-1) || chars('')).downcase
|
360
361
|
end
|
@@ -382,8 +383,8 @@ module ActiveSupport #:nodoc:
|
|
382
383
|
# Performs canonical decomposition on all the characters.
|
383
384
|
#
|
384
385
|
# Example:
|
385
|
-
# 'é'.length
|
386
|
-
# 'é'.mb_chars.decompose.to_s.length
|
386
|
+
# 'é'.length # => 2
|
387
|
+
# 'é'.mb_chars.decompose.to_s.length # => 3
|
387
388
|
def decompose
|
388
389
|
chars(Unicode.decompose_codepoints(:canonical, Unicode.u_unpack(@wrapped_string)).pack('U*'))
|
389
390
|
end
|
@@ -391,8 +392,8 @@ module ActiveSupport #:nodoc:
|
|
391
392
|
# Performs composition on all the characters.
|
392
393
|
#
|
393
394
|
# Example:
|
394
|
-
# 'é'.length
|
395
|
-
# 'é'.mb_chars.compose.to_s.length
|
395
|
+
# 'é'.length # => 3
|
396
|
+
# 'é'.mb_chars.compose.to_s.length # => 2
|
396
397
|
def compose
|
397
398
|
chars(Unicode.compose_codepoints(Unicode.u_unpack(@wrapped_string)).pack('U*'))
|
398
399
|
end
|
@@ -400,8 +401,8 @@ module ActiveSupport #:nodoc:
|
|
400
401
|
# Returns the number of grapheme clusters in the string.
|
401
402
|
#
|
402
403
|
# Example:
|
403
|
-
# 'क्षि'.mb_chars.length
|
404
|
-
# 'क्षि'.mb_chars.g_length
|
404
|
+
# 'क्षि'.mb_chars.length # => 4
|
405
|
+
# 'क्षि'.mb_chars.g_length # => 3
|
405
406
|
def g_length
|
406
407
|
Unicode.g_unpack(@wrapped_string).length
|
407
408
|
end
|
@@ -64,7 +64,7 @@ module ActiveSupport
|
|
64
64
|
# valid UTF-8.
|
65
65
|
#
|
66
66
|
# Example:
|
67
|
-
# Unicode.u_unpack('Café')
|
67
|
+
# Unicode.u_unpack('Café') # => [67, 97, 102, 233]
|
68
68
|
def u_unpack(string)
|
69
69
|
begin
|
70
70
|
string.unpack 'U*'
|
@@ -85,8 +85,8 @@ module ActiveSupport
|
|
85
85
|
# Unpack the string at grapheme boundaries. Returns a list of character lists.
|
86
86
|
#
|
87
87
|
# Example:
|
88
|
-
# Unicode.g_unpack('क्षि')
|
89
|
-
# Unicode.g_unpack('Café')
|
88
|
+
# Unicode.g_unpack('क्षि') # => [[2325, 2381], [2359], [2367]]
|
89
|
+
# Unicode.g_unpack('Café') # => [[67], [97], [102], [233]]
|
90
90
|
def g_unpack(string)
|
91
91
|
codepoints = u_unpack(string)
|
92
92
|
unpacked = []
|
@@ -120,7 +120,7 @@ module ActiveSupport
|
|
120
120
|
# Reverse operation of g_unpack.
|
121
121
|
#
|
122
122
|
# Example:
|
123
|
-
# Unicode.g_pack(Unicode.g_unpack('क्षि'))
|
123
|
+
# Unicode.g_pack(Unicode.g_unpack('क्षि')) # => 'क्षि'
|
124
124
|
def g_pack(unpacked)
|
125
125
|
(unpacked.flatten).pack('U*')
|
126
126
|
end
|
@@ -22,9 +22,9 @@ module ActiveSupport
|
|
22
22
|
# end
|
23
23
|
#
|
24
24
|
# event = @events.first
|
25
|
-
# event.name
|
26
|
-
# event.duration
|
27
|
-
# event.payload
|
25
|
+
# event.name # => :render
|
26
|
+
# event.duration # => 10 (in milliseconds)
|
27
|
+
# event.payload # => { :extra => :information }
|
28
28
|
#
|
29
29
|
# When subscribing to Notifications, you can pass a pattern, to only consume
|
30
30
|
# events that match the pattern:
|
@@ -26,25 +26,25 @@ module ActiveSupport
|
|
26
26
|
# == Example
|
27
27
|
#
|
28
28
|
# # random hexadecimal string.
|
29
|
-
# p SecureRandom.hex(10)
|
30
|
-
# p SecureRandom.hex(10)
|
31
|
-
# p SecureRandom.hex(11)
|
32
|
-
# p SecureRandom.hex(12)
|
33
|
-
# p SecureRandom.hex(13)
|
29
|
+
# p SecureRandom.hex(10) # => "52750b30ffbc7de3b362"
|
30
|
+
# p SecureRandom.hex(10) # => "92b15d6c8dc4beb5f559"
|
31
|
+
# p SecureRandom.hex(11) # => "6aca1b5c58e4863e6b81b8"
|
32
|
+
# p SecureRandom.hex(12) # => "94b2fff3e7fd9b9c391a2306"
|
33
|
+
# p SecureRandom.hex(13) # => "39b290146bea6ce975c37cfc23"
|
34
34
|
# ...
|
35
35
|
#
|
36
36
|
# # random base64 string.
|
37
|
-
# p SecureRandom.base64(10)
|
38
|
-
# p SecureRandom.base64(10)
|
39
|
-
# p SecureRandom.base64(10)
|
40
|
-
# p SecureRandom.base64(11)
|
41
|
-
# p SecureRandom.base64(12)
|
42
|
-
# p SecureRandom.base64(13)
|
37
|
+
# p SecureRandom.base64(10) # => "EcmTPZwWRAozdA=="
|
38
|
+
# p SecureRandom.base64(10) # => "9b0nsevdwNuM/w=="
|
39
|
+
# p SecureRandom.base64(10) # => "KO1nIU+p9DKxGg=="
|
40
|
+
# p SecureRandom.base64(11) # => "l7XEiFja+8EKEtY="
|
41
|
+
# p SecureRandom.base64(12) # => "7kJSM/MzBJI+75j8"
|
42
|
+
# p SecureRandom.base64(13) # => "vKLJ0tXBHqQOuIcSIg=="
|
43
43
|
# ...
|
44
44
|
#
|
45
45
|
# # random binary string.
|
46
|
-
# p SecureRandom.random_bytes(10)
|
47
|
-
# p SecureRandom.random_bytes(10)
|
46
|
+
# p SecureRandom.random_bytes(10) # => "\016\t{\370g\310pbr\301"
|
47
|
+
# p SecureRandom.random_bytes(10) # => "\323U\030TO\234\357\020\a\337"
|
48
48
|
# ...
|
49
49
|
module SecureRandom
|
50
50
|
# SecureRandom.random_bytes generates a random binary string.
|