activesupport 4.0.13 → 4.1.0.beta1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +283 -508
- data/README.rdoc +1 -1
- data/lib/active_support.rb +7 -1
- data/lib/active_support/backtrace_cleaner.rb +5 -5
- data/lib/active_support/benchmarkable.rb +0 -10
- data/lib/active_support/cache.rb +62 -26
- data/lib/active_support/cache/file_store.rb +27 -22
- data/lib/active_support/cache/mem_cache_store.rb +2 -2
- data/lib/active_support/cache/memory_store.rb +1 -0
- data/lib/active_support/cache/strategy/local_cache.rb +3 -0
- data/lib/active_support/callbacks.rb +416 -245
- data/lib/active_support/concern.rb +13 -5
- data/lib/active_support/core_ext.rb +0 -1
- data/lib/active_support/core_ext/array.rb +0 -1
- data/lib/active_support/core_ext/array/access.rb +2 -0
- data/lib/active_support/core_ext/array/conversions.rb +2 -17
- data/lib/active_support/core_ext/array/grouping.rb +24 -12
- data/lib/active_support/core_ext/array/prepend_and_append.rb +2 -2
- data/lib/active_support/core_ext/class.rb +0 -1
- data/lib/active_support/core_ext/class/attribute.rb +1 -2
- data/lib/active_support/core_ext/class/attribute_accessors.rb +5 -169
- data/lib/active_support/core_ext/date/calculations.rb +10 -0
- data/lib/active_support/core_ext/date/conversions.rb +5 -6
- data/lib/active_support/core_ext/date/zones.rb +2 -33
- data/lib/active_support/core_ext/date_and_time/calculations.rb +30 -11
- data/lib/active_support/core_ext/date_and_time/zones.rb +41 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +12 -25
- data/lib/active_support/core_ext/date_time/conversions.rb +2 -0
- data/lib/active_support/core_ext/date_time/zones.rb +3 -21
- data/lib/active_support/core_ext/hash.rb +0 -1
- data/lib/active_support/core_ext/hash/conversions.rb +6 -3
- data/lib/active_support/core_ext/hash/deep_merge.rb +11 -22
- data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -0
- data/lib/active_support/core_ext/hash/keys.rb +27 -47
- data/lib/active_support/core_ext/kernel/reporting.rb +2 -6
- data/lib/active_support/core_ext/module.rb +1 -0
- data/lib/active_support/core_ext/module/attribute_accessors.rb +160 -14
- data/lib/active_support/core_ext/module/concerning.rb +135 -0
- data/lib/active_support/core_ext/module/delegation.rb +14 -4
- data/lib/active_support/core_ext/module/deprecation.rb +0 -2
- data/lib/active_support/core_ext/module/introspection.rb +0 -16
- data/lib/active_support/core_ext/module/method_transplanting.rb +11 -0
- data/lib/active_support/core_ext/numeric/time.rb +8 -0
- data/lib/active_support/core_ext/object.rb +1 -1
- data/lib/active_support/core_ext/object/blank.rb +1 -1
- data/lib/active_support/core_ext/object/deep_dup.rb +6 -6
- data/lib/active_support/core_ext/object/inclusion.rb +4 -15
- data/lib/active_support/core_ext/object/json.rb +197 -0
- data/lib/active_support/core_ext/object/to_json.rb +4 -26
- data/lib/active_support/core_ext/object/to_param.rb +58 -1
- data/lib/active_support/core_ext/object/to_query.rb +7 -56
- data/lib/active_support/core_ext/object/try.rb +1 -1
- data/lib/active_support/core_ext/range/each.rb +2 -1
- data/lib/active_support/core_ext/string/access.rb +31 -31
- data/lib/active_support/core_ext/string/conversions.rb +9 -8
- data/lib/active_support/core_ext/string/exclude.rb +3 -3
- data/lib/active_support/core_ext/string/filters.rb +14 -4
- data/lib/active_support/core_ext/string/inflections.rb +11 -9
- data/lib/active_support/core_ext/string/output_safety.rb +65 -24
- data/lib/active_support/core_ext/string/zones.rb +1 -0
- data/lib/active_support/core_ext/thread.rb +4 -4
- data/lib/active_support/core_ext/time/calculations.rb +10 -57
- data/lib/active_support/core_ext/time/conversions.rb +3 -1
- data/lib/active_support/core_ext/time/zones.rb +2 -21
- data/lib/active_support/dependencies.rb +29 -13
- data/lib/active_support/deprecation.rb +4 -4
- data/lib/active_support/deprecation/behaviors.rb +3 -3
- data/lib/active_support/duration.rb +5 -7
- data/lib/active_support/file_update_checker.rb +1 -1
- data/lib/active_support/hash_with_indifferent_access.rb +4 -9
- data/lib/active_support/i18n.rb +4 -4
- data/lib/active_support/i18n_railtie.rb +2 -6
- data/lib/active_support/inflections.rb +0 -1
- data/lib/active_support/inflector/inflections.rb +17 -17
- data/lib/active_support/inflector/methods.rb +34 -17
- data/lib/active_support/json/decoding.rb +14 -21
- data/lib/active_support/json/encoding.rb +113 -285
- data/lib/active_support/key_generator.rb +1 -1
- data/lib/active_support/lazy_load_hooks.rb +1 -1
- data/lib/active_support/log_subscriber/test_helper.rb +1 -1
- data/lib/active_support/logger.rb +1 -1
- data/lib/active_support/message_encryptor.rb +3 -3
- data/lib/active_support/message_verifier.rb +6 -1
- data/lib/active_support/multibyte/chars.rb +1 -2
- data/lib/active_support/multibyte/unicode.rb +27 -39
- data/lib/active_support/notifications.rb +3 -3
- data/lib/active_support/notifications/instrumenter.rb +2 -1
- data/lib/active_support/number_helper.rb +20 -311
- data/lib/active_support/number_helper/number_converter.rb +182 -0
- data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +21 -0
- data/lib/active_support/number_helper/number_to_human_converter.rb +66 -0
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +58 -0
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +12 -0
- data/lib/active_support/number_helper/number_to_phone_converter.rb +49 -0
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +62 -0
- data/lib/active_support/option_merger.rb +1 -1
- data/lib/active_support/ordered_hash.rb +0 -8
- data/lib/active_support/ordered_options.rb +8 -0
- data/lib/active_support/per_thread_registry.rb +9 -8
- data/lib/active_support/subscriber.rb +26 -3
- data/lib/active_support/test_case.rb +9 -10
- data/lib/active_support/testing/assertions.rb +0 -30
- data/lib/active_support/testing/autorun.rb +2 -2
- data/lib/active_support/testing/declarative.rb +18 -8
- data/lib/active_support/testing/isolation.rb +13 -65
- data/lib/active_support/testing/setup_and_teardown.rb +17 -2
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +55 -0
- data/lib/active_support/time_with_zone.rb +4 -4
- data/lib/active_support/values/time_zone.rb +18 -15
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini.rb +2 -4
- metadata +71 -61
- data/lib/active_support/basic_object.rb +0 -11
- data/lib/active_support/buffered_logger.rb +0 -21
- data/lib/active_support/core_ext/array/uniq_by.rb +0 -19
- data/lib/active_support/core_ext/hash/diff.rb +0 -14
- data/lib/active_support/core_ext/logger.rb +0 -67
- data/lib/active_support/core_ext/proc.rb +0 -17
- data/lib/active_support/core_ext/string/encoding.rb +0 -8
- data/lib/active_support/json/variable.rb +0 -18
- data/lib/active_support/testing/pending.rb +0 -14
@@ -47,7 +47,7 @@ class Object
|
|
47
47
|
end
|
48
48
|
|
49
49
|
# Same as #try, but will raise a NoMethodError exception if the receiving is not nil and
|
50
|
-
# does not
|
50
|
+
# does not implement the tried method.
|
51
51
|
def try!(*a, &b)
|
52
52
|
if a.empty? && block_given?
|
53
53
|
yield self
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'active_support/core_ext/module/aliasing'
|
2
|
+
require 'active_support/core_ext/object/acts_like'
|
2
3
|
|
3
4
|
class Range #:nodoc:
|
4
5
|
|
@@ -16,7 +17,7 @@ class Range #:nodoc:
|
|
16
17
|
|
17
18
|
private
|
18
19
|
def ensure_iteration_allowed
|
19
|
-
if first.
|
20
|
+
if first.acts_like?(:time)
|
20
21
|
raise TypeError, "can't iterate from #{first.class}"
|
21
22
|
end
|
22
23
|
end
|
@@ -8,22 +8,22 @@ class String
|
|
8
8
|
# the beginning of the range is greater than the end of the string.
|
9
9
|
#
|
10
10
|
# str = "hello"
|
11
|
-
# str.at(0)
|
12
|
-
# str.at(1..3)
|
13
|
-
# str.at(-2)
|
14
|
-
# str.at(-2..-1)
|
15
|
-
# str.at(5)
|
16
|
-
# str.at(5..-1)
|
11
|
+
# str.at(0) # => "h"
|
12
|
+
# str.at(1..3) # => "ell"
|
13
|
+
# str.at(-2) # => "l"
|
14
|
+
# str.at(-2..-1) # => "lo"
|
15
|
+
# str.at(5) # => nil
|
16
|
+
# str.at(5..-1) # => ""
|
17
17
|
#
|
18
18
|
# If a Regexp is given, the matching portion of the string is returned.
|
19
19
|
# If a String is given, that given string is returned if it occurs in
|
20
20
|
# the string. In both cases, nil is returned if there is no match.
|
21
21
|
#
|
22
22
|
# str = "hello"
|
23
|
-
# str.at(/lo/)
|
24
|
-
# str.at(/ol/)
|
25
|
-
# str.at("lo")
|
26
|
-
# str.at("ol")
|
23
|
+
# str.at(/lo/) # => "lo"
|
24
|
+
# str.at(/ol/) # => nil
|
25
|
+
# str.at("lo") # => "lo"
|
26
|
+
# str.at("ol") # => nil
|
27
27
|
def at(position)
|
28
28
|
self[position]
|
29
29
|
end
|
@@ -32,15 +32,15 @@ class String
|
|
32
32
|
# If the position is negative, it is counted from the end of the string.
|
33
33
|
#
|
34
34
|
# str = "hello"
|
35
|
-
# str.from(0)
|
36
|
-
# str.from(3)
|
37
|
-
# str.from(-2)
|
35
|
+
# str.from(0) # => "hello"
|
36
|
+
# str.from(3) # => "lo"
|
37
|
+
# str.from(-2) # => "lo"
|
38
38
|
#
|
39
39
|
# You can mix it with +to+ method and do fun things like:
|
40
40
|
#
|
41
41
|
# str = "hello"
|
42
|
-
# str.from(0).to(-1)
|
43
|
-
# str.from(1).to(-2)
|
42
|
+
# str.from(0).to(-1) # => "hello"
|
43
|
+
# str.from(1).to(-2) # => "ell"
|
44
44
|
def from(position)
|
45
45
|
self[position..-1]
|
46
46
|
end
|
@@ -49,17 +49,17 @@ class String
|
|
49
49
|
# If the position is negative, it is counted from the end of the string.
|
50
50
|
#
|
51
51
|
# str = "hello"
|
52
|
-
# str.to(0)
|
53
|
-
# str.to(3)
|
54
|
-
# str.to(-2)
|
52
|
+
# str.to(0) # => "h"
|
53
|
+
# str.to(3) # => "hell"
|
54
|
+
# str.to(-2) # => "hell"
|
55
55
|
#
|
56
56
|
# You can mix it with +from+ method and do fun things like:
|
57
57
|
#
|
58
58
|
# str = "hello"
|
59
|
-
# str.from(0).to(-1)
|
60
|
-
# str.from(1).to(-2)
|
59
|
+
# str.from(0).to(-1) # => "hello"
|
60
|
+
# str.from(1).to(-2) # => "ell"
|
61
61
|
def to(position)
|
62
|
-
self[0
|
62
|
+
self[0, position + 1]
|
63
63
|
end
|
64
64
|
|
65
65
|
# Returns the first character. If a limit is supplied, returns a substring
|
@@ -67,11 +67,11 @@ class String
|
|
67
67
|
# given limit is greater than or equal to the string length, returns self.
|
68
68
|
#
|
69
69
|
# str = "hello"
|
70
|
-
# str.first
|
71
|
-
# str.first(1)
|
72
|
-
# str.first(2)
|
73
|
-
# str.first(0)
|
74
|
-
# str.first(6)
|
70
|
+
# str.first # => "h"
|
71
|
+
# str.first(1) # => "h"
|
72
|
+
# str.first(2) # => "he"
|
73
|
+
# str.first(0) # => ""
|
74
|
+
# str.first(6) # => "hello"
|
75
75
|
def first(limit = 1)
|
76
76
|
if limit == 0
|
77
77
|
''
|
@@ -87,11 +87,11 @@ class String
|
|
87
87
|
# the given limit is greater than or equal to the string length, returns self.
|
88
88
|
#
|
89
89
|
# str = "hello"
|
90
|
-
# str.last
|
91
|
-
# str.last(1)
|
92
|
-
# str.last(2)
|
93
|
-
# str.last(0)
|
94
|
-
# str.last(6)
|
90
|
+
# str.last # => "o"
|
91
|
+
# str.last(1) # => "o"
|
92
|
+
# str.last(2) # => "lo"
|
93
|
+
# str.last(0) # => ""
|
94
|
+
# str.last(6) # => "hello"
|
95
95
|
def last(limit = 1)
|
96
96
|
if limit == 0
|
97
97
|
''
|
@@ -15,6 +15,7 @@ class String
|
|
15
15
|
# "2012-12-13 06:12".to_time # => 2012-12-13 06:12:00 +0100
|
16
16
|
# "2012-12-13T06:12".to_time # => 2012-12-13 06:12:00 +0100
|
17
17
|
# "2012-12-13T06:12".to_time(:utc) # => 2012-12-13 05:12:00 UTC
|
18
|
+
# "12/13/2012".to_time # => ArgumentError: argument out of range
|
18
19
|
def to_time(form = :local)
|
19
20
|
parts = Date._parse(self, false)
|
20
21
|
return if parts.empty?
|
@@ -35,20 +36,20 @@ class String
|
|
35
36
|
|
36
37
|
# Converts a string to a Date value.
|
37
38
|
#
|
38
|
-
# "1-1-2012".to_date
|
39
|
-
# "01/01/2012".to_date
|
40
|
-
# "2012-12-13".to_date
|
41
|
-
# "12/13/2012".to_date
|
39
|
+
# "1-1-2012".to_date # => Sun, 01 Jan 2012
|
40
|
+
# "01/01/2012".to_date # => Sun, 01 Jan 2012
|
41
|
+
# "2012-12-13".to_date # => Thu, 13 Dec 2012
|
42
|
+
# "12/13/2012".to_date # => ArgumentError: invalid date
|
42
43
|
def to_date
|
43
44
|
::Date.parse(self, false) unless blank?
|
44
45
|
end
|
45
46
|
|
46
47
|
# Converts a string to a DateTime value.
|
47
48
|
#
|
48
|
-
# "1-1-2012".to_datetime
|
49
|
-
# "01/01/2012 23:59:59".to_datetime
|
50
|
-
# "2012-12-13 12:50".to_datetime
|
51
|
-
# "12/13/2012".to_datetime
|
49
|
+
# "1-1-2012".to_datetime # => Sun, 01 Jan 2012 00:00:00 +0000
|
50
|
+
# "01/01/2012 23:59:59".to_datetime # => Sun, 01 Jan 2012 23:59:59 +0000
|
51
|
+
# "2012-12-13 12:50".to_datetime # => Thu, 13 Dec 2012 12:50:00 +0000
|
52
|
+
# "12/13/2012".to_datetime # => ArgumentError: invalid date
|
52
53
|
def to_datetime
|
53
54
|
::DateTime.parse(self, false) unless blank?
|
54
55
|
end
|
@@ -2,9 +2,9 @@ class String
|
|
2
2
|
# The inverse of <tt>String#include?</tt>. Returns true if the string
|
3
3
|
# does not include the other string.
|
4
4
|
#
|
5
|
-
# "hello".exclude? "lo"
|
6
|
-
# "hello".exclude? "ol"
|
7
|
-
# "hello".exclude? ?h
|
5
|
+
# "hello".exclude? "lo" # => false
|
6
|
+
# "hello".exclude? "ol" # => true
|
7
|
+
# "hello".exclude? ?h # => false
|
8
8
|
def exclude?(string)
|
9
9
|
!include?(string)
|
10
10
|
end
|
@@ -3,7 +3,7 @@ class String
|
|
3
3
|
# the string, and then changing remaining consecutive whitespace
|
4
4
|
# groups into one space each.
|
5
5
|
#
|
6
|
-
# Note that it handles both ASCII and Unicode whitespace.
|
6
|
+
# Note that it handles both ASCII and Unicode whitespace like mongolian vowel separator (U+180E).
|
7
7
|
#
|
8
8
|
# %{ Multi-line
|
9
9
|
# string }.squish # => "Multi-line string"
|
@@ -20,6 +20,16 @@ class String
|
|
20
20
|
self
|
21
21
|
end
|
22
22
|
|
23
|
+
# Returns a new string with all occurrences of the pattern removed. Short-hand for String#gsub(pattern, '').
|
24
|
+
def remove(pattern)
|
25
|
+
gsub pattern, ''
|
26
|
+
end
|
27
|
+
|
28
|
+
# Alters the string by removing all occurrences of the pattern. Short-hand for String#gsub!(pattern, '').
|
29
|
+
def remove!(pattern)
|
30
|
+
gsub! pattern, ''
|
31
|
+
end
|
32
|
+
|
23
33
|
# Truncates a given +text+ after a given <tt>length</tt> if +text+ is longer than <tt>length</tt>:
|
24
34
|
#
|
25
35
|
# 'Once upon a time in a world far far away'.truncate(27)
|
@@ -41,8 +51,8 @@ class String
|
|
41
51
|
def truncate(truncate_at, options = {})
|
42
52
|
return dup unless length > truncate_at
|
43
53
|
|
44
|
-
options[:omission]
|
45
|
-
length_with_room_for_omission = truncate_at -
|
54
|
+
omission = options[:omission] || '...'
|
55
|
+
length_with_room_for_omission = truncate_at - omission.length
|
46
56
|
stop = \
|
47
57
|
if options[:separator]
|
48
58
|
rindex(options[:separator], length_with_room_for_omission) || length_with_room_for_omission
|
@@ -50,6 +60,6 @@ class String
|
|
50
60
|
length_with_room_for_omission
|
51
61
|
end
|
52
62
|
|
53
|
-
"#{self[0
|
63
|
+
"#{self[0, stop]}#{omission}"
|
54
64
|
end
|
55
65
|
end
|
@@ -182,21 +182,23 @@ class String
|
|
182
182
|
#
|
183
183
|
# 'egg_and_hams'.classify # => "EggAndHam"
|
184
184
|
# 'posts'.classify # => "Post"
|
185
|
-
#
|
186
|
-
# Singular names are not handled correctly.
|
187
|
-
#
|
188
|
-
# 'business'.classify # => "Busines"
|
189
185
|
def classify
|
190
186
|
ActiveSupport::Inflector.classify(self)
|
191
187
|
end
|
192
188
|
|
193
|
-
# Capitalizes the first word, turns underscores into spaces, and strips
|
189
|
+
# Capitalizes the first word, turns underscores into spaces, and strips a
|
190
|
+
# trailing '_id' if present.
|
194
191
|
# Like +titleize+, this is meant for creating pretty output.
|
195
192
|
#
|
196
|
-
#
|
197
|
-
#
|
198
|
-
|
199
|
-
|
193
|
+
# The capitalization of the first word can be turned off by setting the
|
194
|
+
# optional parameter +capitalize+ to false.
|
195
|
+
# By default, this parameter is true.
|
196
|
+
#
|
197
|
+
# 'employee_salary'.humanize # => "Employee salary"
|
198
|
+
# 'author_id'.humanize # => "Author"
|
199
|
+
# 'author_id'.humanize(capitalize: false) # => "author"
|
200
|
+
def humanize(options = {})
|
201
|
+
ActiveSupport::Inflector.humanize(self, options)
|
200
202
|
end
|
201
203
|
|
202
204
|
# Creates a foreign key name from a class name.
|
@@ -4,9 +4,10 @@ require 'active_support/core_ext/kernel/singleton_class'
|
|
4
4
|
class ERB
|
5
5
|
module Util
|
6
6
|
HTML_ESCAPE = { '&' => '&', '>' => '>', '<' => '<', '"' => '"', "'" => ''' }
|
7
|
-
JSON_ESCAPE = { '&' => '\u0026', '>' => '\
|
7
|
+
JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003e', '<' => '\u003c', "\u2028" => '\u2028', "\u2029" => '\u2029' }
|
8
|
+
HTML_ESCAPE_REGEXP = /[&"'><]/
|
8
9
|
HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+));)/
|
9
|
-
JSON_ESCAPE_REGEXP = /[
|
10
|
+
JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/u
|
10
11
|
|
11
12
|
# A utility method for escaping HTML tag characters.
|
12
13
|
# This method is also aliased as <tt>h</tt>.
|
@@ -21,7 +22,7 @@ class ERB
|
|
21
22
|
if s.html_safe?
|
22
23
|
s
|
23
24
|
else
|
24
|
-
s.gsub(
|
25
|
+
s.gsub(HTML_ESCAPE_REGEXP, HTML_ESCAPE).html_safe
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
@@ -48,17 +49,56 @@ class ERB
|
|
48
49
|
|
49
50
|
module_function :html_escape_once
|
50
51
|
|
51
|
-
# A utility method for escaping HTML entities in JSON strings
|
52
|
-
#
|
52
|
+
# A utility method for escaping HTML entities in JSON strings. Specifically, the
|
53
|
+
# &, > and < characters are replaced with their equivalent unicode escaped form -
|
54
|
+
# \u0026, \u003e, and \u003c. The Unicode sequences \u2028 and \u2029 are also
|
55
|
+
# escaped as they are treated as newline characters in some JavaScript engines.
|
56
|
+
# These sequences have identical meaning as the original characters inside the
|
57
|
+
# context of a JSON string, so assuming the input is a valid and well-formed
|
58
|
+
# JSON value, the output will have equivalent meaning when parsed:
|
53
59
|
#
|
54
|
-
#
|
55
|
-
# # =>
|
60
|
+
# json = JSON.generate({ name: "</script><script>alert('PWNED!!!')</script>"})
|
61
|
+
# # => "{\"name\":\"</script><script>alert('PWNED!!!')</script>\"}"
|
56
62
|
#
|
57
|
-
#
|
58
|
-
#
|
63
|
+
# json_escape(json)
|
64
|
+
# # => "{\"name\":\"\\u003C/script\\u003E\\u003Cscript\\u003Ealert('PWNED!!!')\\u003C/script\\u003E\"}"
|
65
|
+
#
|
66
|
+
# JSON.parse(json) == JSON.parse(json_escape(json))
|
67
|
+
# # => true
|
68
|
+
#
|
69
|
+
# The intended use case for this method is to escape JSON strings before including
|
70
|
+
# them inside a script tag to avoid XSS vulnerability:
|
71
|
+
#
|
72
|
+
# <script>
|
73
|
+
# var currentUser = <%= json_escape current_user.to_json %>;
|
74
|
+
# </script>
|
75
|
+
#
|
76
|
+
# WARNING: this helper only works with valid JSON. Using this on non-JSON values
|
77
|
+
# will open up serious XSS vulnerabilities. For example, if you replace the
|
78
|
+
# +current_user.to_json+ in the example above with user input instead, the browser
|
79
|
+
# will happily eval() that string as JavaScript.
|
80
|
+
#
|
81
|
+
# The escaping performed in this method is identical to those performed in the
|
82
|
+
# Active Support JSON encoder when +ActiveSupport.escape_html_entities_in_json+ is
|
83
|
+
# set to true. Because this transformation is idempotent, this helper can be
|
84
|
+
# applied even if +ActiveSupport.escape_html_entities_in_json+ is already true.
|
85
|
+
#
|
86
|
+
# Therefore, when you are unsure if +ActiveSupport.escape_html_entities_in_json+
|
87
|
+
# is enabled, or if you are unsure where your JSON string originated from, it
|
88
|
+
# is recommended that you always apply this helper (other libraries, such as the
|
89
|
+
# JSON gem, do not provide this kind of protection by default; also some gems
|
90
|
+
# might override +to_json+ to bypass Active Support's encoder).
|
91
|
+
#
|
92
|
+
# The output of this helper method is marked as HTML safe so that you can directly
|
93
|
+
# include it inside a <tt><script></tt> tag as shown above.
|
94
|
+
#
|
95
|
+
# However, it is NOT safe to use the output of this inside an HTML attribute,
|
96
|
+
# because quotation marks are not escaped. Doing so might break your page's layout.
|
97
|
+
# If you intend to use this inside an HTML attribute, you should use the
|
98
|
+
# +html_escape+ helper (or its +h+ alias) instead:
|
99
|
+
#
|
100
|
+
# <div data-user-info="<%= h current_user.to_json %>">...</div>
|
59
101
|
#
|
60
|
-
# json_escape('{"name":"john","created_at":"2010-04-28T01:39:31Z","id":1}')
|
61
|
-
# # => {name:john,created_at:2010-04-28T01:39:31Z,id:1}
|
62
102
|
def json_escape(s)
|
63
103
|
result = s.to_s.gsub(JSON_ESCAPE_REGEXP, JSON_ESCAPE)
|
64
104
|
s.html_safe? ? result.html_safe : result
|
@@ -102,11 +142,7 @@ module ActiveSupport #:nodoc:
|
|
102
142
|
else
|
103
143
|
if html_safe?
|
104
144
|
new_safe_buffer = super
|
105
|
-
|
106
|
-
if new_safe_buffer
|
107
|
-
new_safe_buffer.instance_eval { @html_safe = true }
|
108
|
-
end
|
109
|
-
|
145
|
+
new_safe_buffer.instance_eval { @html_safe = true }
|
110
146
|
new_safe_buffer
|
111
147
|
else
|
112
148
|
to_str[*args]
|
@@ -147,15 +183,14 @@ module ActiveSupport #:nodoc:
|
|
147
183
|
end
|
148
184
|
|
149
185
|
def %(args)
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
end
|
186
|
+
case args
|
187
|
+
when Hash
|
188
|
+
escaped_args = Hash[args.map { |k,arg| [k, html_escape_interpolated_argument(arg)] }]
|
189
|
+
else
|
190
|
+
escaped_args = Array(args).map { |arg| html_escape_interpolated_argument(arg) }
|
156
191
|
end
|
157
192
|
|
158
|
-
self.class.new(super(
|
193
|
+
self.class.new(super(escaped_args))
|
159
194
|
end
|
160
195
|
|
161
196
|
def html_safe?
|
@@ -175,7 +210,7 @@ module ActiveSupport #:nodoc:
|
|
175
210
|
end
|
176
211
|
|
177
212
|
UNSAFE_STRING_METHODS.each do |unsafe_method|
|
178
|
-
if
|
213
|
+
if unsafe_method.respond_to?(unsafe_method)
|
179
214
|
class_eval <<-EOT, __FILE__, __LINE__ + 1
|
180
215
|
def #{unsafe_method}(*args, &block) # def capitalize(*args, &block)
|
181
216
|
to_str.#{unsafe_method}(*args, &block) # to_str.capitalize(*args, &block)
|
@@ -188,6 +223,12 @@ module ActiveSupport #:nodoc:
|
|
188
223
|
EOT
|
189
224
|
end
|
190
225
|
end
|
226
|
+
|
227
|
+
private
|
228
|
+
|
229
|
+
def html_escape_interpolated_argument(arg)
|
230
|
+
(!html_safe? || arg.html_safe?) ? arg : ERB::Util.h(arg)
|
231
|
+
end
|
191
232
|
end
|
192
233
|
end
|
193
234
|
|
@@ -39,8 +39,8 @@ class Thread
|
|
39
39
|
# Thread.current.thread_variable_set(:cat, 'meow')
|
40
40
|
# Thread.current.thread_variable_set("dog", 'woof')
|
41
41
|
# end
|
42
|
-
# thr.join
|
43
|
-
# thr.thread_variables
|
42
|
+
# thr.join # => #<Thread:0x401b3f10 dead>
|
43
|
+
# thr.thread_variables # => [:dog, :cat]
|
44
44
|
#
|
45
45
|
# Note that these are not fiber local variables. Please see Thread#thread_variable_get
|
46
46
|
# for more details.
|
@@ -53,8 +53,8 @@ class Thread
|
|
53
53
|
#
|
54
54
|
# me = Thread.current
|
55
55
|
# me.thread_variable_set(:oliver, "a")
|
56
|
-
# me.thread_variable?(:oliver)
|
57
|
-
# me.thread_variable?(:stanley)
|
56
|
+
# me.thread_variable?(:oliver) # => true
|
57
|
+
# me.thread_variable?(:stanley) # => false
|
58
58
|
#
|
59
59
|
# Note that these are not fiber local variables. Please see Thread#thread_variable_get
|
60
60
|
# for more details.
|
@@ -3,7 +3,6 @@ require 'active_support/core_ext/time/conversions'
|
|
3
3
|
require 'active_support/time_with_zone'
|
4
4
|
require 'active_support/core_ext/time/zones'
|
5
5
|
require 'active_support/core_ext/date_and_time/calculations'
|
6
|
-
require 'active_support/deprecation'
|
7
6
|
|
8
7
|
class Time
|
9
8
|
include DateAndTime::Calculations
|
@@ -26,41 +25,6 @@ class Time
|
|
26
25
|
end
|
27
26
|
end
|
28
27
|
|
29
|
-
# *DEPRECATED*: Use +Time#utc+ or +Time#local+ instead.
|
30
|
-
#
|
31
|
-
# Returns a new Time if requested year can be accommodated by Ruby's Time class
|
32
|
-
# (i.e., if year is within either 1970..2038 or 1902..2038, depending on system architecture);
|
33
|
-
# otherwise returns a DateTime.
|
34
|
-
def time_with_datetime_fallback(utc_or_local, year, month=1, day=1, hour=0, min=0, sec=0, usec=0)
|
35
|
-
ActiveSupport::Deprecation.warn 'time_with_datetime_fallback is deprecated. Use Time#utc or Time#local instead', caller
|
36
|
-
time = ::Time.send(utc_or_local, year, month, day, hour, min, sec, usec)
|
37
|
-
|
38
|
-
# This check is needed because Time.utc(y) returns a time object in the 2000s for 0 <= y <= 138.
|
39
|
-
if time.year == year
|
40
|
-
time
|
41
|
-
else
|
42
|
-
::DateTime.civil_from_format(utc_or_local, year, month, day, hour, min, sec)
|
43
|
-
end
|
44
|
-
rescue
|
45
|
-
::DateTime.civil_from_format(utc_or_local, year, month, day, hour, min, sec)
|
46
|
-
end
|
47
|
-
|
48
|
-
# *DEPRECATED*: Use +Time#utc+ instead.
|
49
|
-
#
|
50
|
-
# Wraps class method +time_with_datetime_fallback+ with +utc_or_local+ set to <tt>:utc</tt>.
|
51
|
-
def utc_time(*args)
|
52
|
-
ActiveSupport::Deprecation.warn 'utc_time is deprecated. Use Time#utc instead', caller
|
53
|
-
time_with_datetime_fallback(:utc, *args)
|
54
|
-
end
|
55
|
-
|
56
|
-
# *DEPRECATED*: Use +Time#local+ instead.
|
57
|
-
#
|
58
|
-
# Wraps class method +time_with_datetime_fallback+ with +utc_or_local+ set to <tt>:local</tt>.
|
59
|
-
def local_time(*args)
|
60
|
-
ActiveSupport::Deprecation.warn 'local_time is deprecated. Use Time#local instead', caller
|
61
|
-
time_with_datetime_fallback(:local, *args)
|
62
|
-
end
|
63
|
-
|
64
28
|
# Returns <tt>Time.zone.now</tt> when <tt>Time.zone</tt> or <tt>config.time_zone</tt> are set, otherwise just returns <tt>Time.now</tt>.
|
65
29
|
def current
|
66
30
|
::Time.zone ? ::Time.zone.now : ::Time.now
|
@@ -178,6 +142,16 @@ class Time
|
|
178
142
|
alias :at_midnight :beginning_of_day
|
179
143
|
alias :at_beginning_of_day :beginning_of_day
|
180
144
|
|
145
|
+
# Returns a new Time representing the middle of the day (12:00)
|
146
|
+
def middle_of_day
|
147
|
+
change(:hour => 12)
|
148
|
+
end
|
149
|
+
alias :midday :middle_of_day
|
150
|
+
alias :noon :middle_of_day
|
151
|
+
alias :at_midday :middle_of_day
|
152
|
+
alias :at_noon :middle_of_day
|
153
|
+
alias :at_middle_of_day :middle_of_day
|
154
|
+
|
181
155
|
# Returns a new Time representing the end of the day, 23:59:59.999999 (.999999999 in ruby1.9)
|
182
156
|
def end_of_day
|
183
157
|
change(
|
@@ -225,27 +199,6 @@ class Time
|
|
225
199
|
beginning_of_day..end_of_day
|
226
200
|
end
|
227
201
|
|
228
|
-
# Returns a Range representing the whole week of the current time.
|
229
|
-
# Week starts on start_day, default is <tt>Date.week_start</tt> or <tt>config.week_start</tt> when set.
|
230
|
-
def all_week(start_day = Date.beginning_of_week)
|
231
|
-
beginning_of_week(start_day)..end_of_week(start_day)
|
232
|
-
end
|
233
|
-
|
234
|
-
# Returns a Range representing the whole month of the current time.
|
235
|
-
def all_month
|
236
|
-
beginning_of_month..end_of_month
|
237
|
-
end
|
238
|
-
|
239
|
-
# Returns a Range representing the whole quarter of the current time.
|
240
|
-
def all_quarter
|
241
|
-
beginning_of_quarter..end_of_quarter
|
242
|
-
end
|
243
|
-
|
244
|
-
# Returns a Range representing the whole year of the current time.
|
245
|
-
def all_year
|
246
|
-
beginning_of_year..end_of_year
|
247
|
-
end
|
248
|
-
|
249
202
|
def plus_with_duration(other) #:nodoc:
|
250
203
|
if ActiveSupport::Duration === other
|
251
204
|
other.since(self)
|