activesupport 4.0.13 → 4.2.11.3

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.

Files changed (166) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +406 -418
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +7 -2
  5. data/lib/active_support/backtrace_cleaner.rb +8 -8
  6. data/lib/active_support/benchmarkable.rb +0 -10
  7. data/lib/active_support/cache/file_store.rb +32 -22
  8. data/lib/active_support/cache/mem_cache_store.rb +5 -7
  9. data/lib/active_support/cache/memory_store.rb +1 -0
  10. data/lib/active_support/cache/strategy/local_cache.rb +11 -30
  11. data/lib/active_support/cache/strategy/local_cache_middleware.rb +44 -0
  12. data/lib/active_support/cache.rb +75 -41
  13. data/lib/active_support/callbacks.rb +482 -261
  14. data/lib/active_support/concern.rb +23 -7
  15. data/lib/active_support/configurable.rb +1 -1
  16. data/lib/active_support/core_ext/array/access.rb +11 -1
  17. data/lib/active_support/core_ext/array/conversions.rb +2 -17
  18. data/lib/active_support/core_ext/array/grouping.rb +29 -12
  19. data/lib/active_support/core_ext/array/prepend_and_append.rb +2 -2
  20. data/lib/active_support/core_ext/array.rb +0 -1
  21. data/lib/active_support/core_ext/big_decimal/conversions.rb +0 -15
  22. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +16 -0
  23. data/lib/active_support/core_ext/class/attribute.rb +1 -2
  24. data/lib/active_support/core_ext/class/attribute_accessors.rb +4 -170
  25. data/lib/active_support/core_ext/class/delegating_attributes.rb +13 -8
  26. data/lib/active_support/core_ext/class/subclasses.rb +0 -2
  27. data/lib/active_support/core_ext/class.rb +0 -1
  28. data/lib/active_support/core_ext/date/calculations.rb +10 -0
  29. data/lib/active_support/core_ext/date/conversions.rb +9 -1
  30. data/lib/active_support/core_ext/date/zones.rb +2 -33
  31. data/lib/active_support/core_ext/date_and_time/calculations.rb +41 -11
  32. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  33. data/lib/active_support/core_ext/date_and_time/zones.rb +41 -0
  34. data/lib/active_support/core_ext/date_time/calculations.rb +45 -22
  35. data/lib/active_support/core_ext/date_time/compatibility.rb +16 -0
  36. data/lib/active_support/core_ext/date_time/conversions.rb +4 -2
  37. data/lib/active_support/core_ext/date_time/zones.rb +3 -21
  38. data/lib/active_support/core_ext/date_time.rb +1 -0
  39. data/lib/active_support/core_ext/digest/uuid.rb +51 -0
  40. data/lib/active_support/core_ext/enumerable.rb +17 -1
  41. data/lib/active_support/core_ext/file/atomic.rb +1 -1
  42. data/lib/active_support/core_ext/hash/compact.rb +24 -0
  43. data/lib/active_support/core_ext/hash/conversions.rb +9 -8
  44. data/lib/active_support/core_ext/hash/except.rb +8 -2
  45. data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -0
  46. data/lib/active_support/core_ext/hash/keys.rb +25 -19
  47. data/lib/active_support/core_ext/hash/slice.rb +8 -2
  48. data/lib/active_support/core_ext/hash/transform_values.rb +23 -0
  49. data/lib/active_support/core_ext/hash.rb +2 -1
  50. data/lib/active_support/core_ext/integer/time.rb +0 -15
  51. data/lib/active_support/core_ext/kernel/concern.rb +10 -0
  52. data/lib/active_support/core_ext/kernel/debugger.rb +1 -1
  53. data/lib/active_support/core_ext/kernel/reporting.rb +13 -2
  54. data/lib/active_support/core_ext/kernel.rb +3 -2
  55. data/lib/active_support/core_ext/load_error.rb +4 -1
  56. data/lib/active_support/core_ext/marshal.rb +8 -5
  57. data/lib/active_support/core_ext/module/aliasing.rb +2 -2
  58. data/lib/active_support/core_ext/module/attr_internal.rb +2 -1
  59. data/lib/active_support/core_ext/module/attribute_accessors.rb +160 -14
  60. data/lib/active_support/core_ext/module/concerning.rb +135 -0
  61. data/lib/active_support/core_ext/module/delegation.rb +53 -25
  62. data/lib/active_support/core_ext/module/deprecation.rb +0 -2
  63. data/lib/active_support/core_ext/module/introspection.rb +0 -16
  64. data/lib/active_support/core_ext/module/method_transplanting.rb +13 -0
  65. data/lib/active_support/core_ext/module.rb +1 -0
  66. data/lib/active_support/core_ext/numeric/conversions.rb +11 -3
  67. data/lib/active_support/core_ext/numeric/time.rb +4 -29
  68. data/lib/active_support/core_ext/object/blank.rb +44 -18
  69. data/lib/active_support/core_ext/object/deep_dup.rb +6 -6
  70. data/lib/active_support/core_ext/object/duplicable.rb +72 -33
  71. data/lib/active_support/core_ext/object/inclusion.rb +16 -15
  72. data/lib/active_support/core_ext/object/itself.rb +15 -0
  73. data/lib/active_support/core_ext/object/json.rb +197 -0
  74. data/lib/active_support/core_ext/object/to_query.rb +14 -6
  75. data/lib/active_support/core_ext/object/try.rb +36 -14
  76. data/lib/active_support/core_ext/object/with_options.rb +30 -3
  77. data/lib/active_support/core_ext/object.rb +2 -1
  78. data/lib/active_support/core_ext/string/access.rb +35 -35
  79. data/lib/active_support/core_ext/string/conversions.rb +10 -9
  80. data/lib/active_support/core_ext/string/exclude.rb +3 -3
  81. data/lib/active_support/core_ext/string/filters.rb +51 -3
  82. data/lib/active_support/core_ext/string/inflections.rb +15 -10
  83. data/lib/active_support/core_ext/string/output_safety.rb +97 -33
  84. data/lib/active_support/core_ext/string/zones.rb +1 -0
  85. data/lib/active_support/core_ext/thread.rb +12 -5
  86. data/lib/active_support/core_ext/time/calculations.rb +47 -68
  87. data/lib/active_support/core_ext/time/compatibility.rb +14 -0
  88. data/lib/active_support/core_ext/time/conversions.rb +4 -2
  89. data/lib/active_support/core_ext/time/zones.rb +2 -20
  90. data/lib/active_support/core_ext/time.rb +1 -0
  91. data/lib/active_support/core_ext.rb +0 -1
  92. data/lib/active_support/dependencies/autoload.rb +1 -1
  93. data/lib/active_support/dependencies.rb +64 -25
  94. data/lib/active_support/deprecation/behaviors.rb +4 -4
  95. data/lib/active_support/deprecation.rb +4 -4
  96. data/lib/active_support/duration.rb +55 -11
  97. data/lib/active_support/file_update_checker.rb +1 -1
  98. data/lib/active_support/gem_version.rb +15 -0
  99. data/lib/active_support/hash_with_indifferent_access.rb +39 -11
  100. data/lib/active_support/i18n.rb +4 -4
  101. data/lib/active_support/i18n_railtie.rb +1 -7
  102. data/lib/active_support/inflections.rb +6 -1
  103. data/lib/active_support/inflector/inflections.rb +19 -19
  104. data/lib/active_support/inflector/methods.rb +66 -25
  105. data/lib/active_support/json/decoding.rb +15 -22
  106. data/lib/active_support/json/encoding.rb +125 -286
  107. data/lib/active_support/key_generator.rb +8 -10
  108. data/lib/active_support/lazy_load_hooks.rb +1 -1
  109. data/lib/active_support/log_subscriber/test_helper.rb +1 -1
  110. data/lib/active_support/logger.rb +51 -1
  111. data/lib/active_support/logger_silence.rb +7 -4
  112. data/lib/active_support/logger_thread_safe_level.rb +32 -0
  113. data/lib/active_support/message_encryptor.rb +14 -6
  114. data/lib/active_support/message_verifier.rb +16 -12
  115. data/lib/active_support/multibyte/chars.rb +2 -3
  116. data/lib/active_support/multibyte/unicode.rb +46 -58
  117. data/lib/active_support/notifications/fanout.rb +12 -7
  118. data/lib/active_support/notifications/instrumenter.rb +2 -1
  119. data/lib/active_support/notifications.rb +11 -6
  120. data/lib/active_support/number_helper/number_converter.rb +182 -0
  121. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  122. data/lib/active_support/number_helper/number_to_delimited_converter.rb +23 -0
  123. data/lib/active_support/number_helper/number_to_human_converter.rb +66 -0
  124. data/lib/active_support/number_helper/number_to_human_size_converter.rb +58 -0
  125. data/lib/active_support/number_helper/number_to_percentage_converter.rb +12 -0
  126. data/lib/active_support/number_helper/number_to_phone_converter.rb +49 -0
  127. data/lib/active_support/number_helper/number_to_rounded_converter.rb +87 -0
  128. data/lib/active_support/number_helper.rb +32 -324
  129. data/lib/active_support/ordered_options.rb +8 -0
  130. data/lib/active_support/per_thread_registry.rb +13 -10
  131. data/lib/active_support/security_utils.rb +27 -0
  132. data/lib/active_support/subscriber.rb +35 -3
  133. data/lib/active_support/test_case.rb +52 -19
  134. data/lib/active_support/testing/assertions.rb +1 -31
  135. data/lib/active_support/testing/autorun.rb +2 -2
  136. data/lib/active_support/testing/constant_lookup.rb +1 -5
  137. data/lib/active_support/testing/declarative.rb +7 -21
  138. data/lib/active_support/testing/isolation.rb +29 -69
  139. data/lib/active_support/testing/setup_and_teardown.rb +17 -2
  140. data/lib/active_support/testing/tagged_logging.rb +2 -2
  141. data/lib/active_support/testing/time_helpers.rb +134 -0
  142. data/lib/active_support/time.rb +0 -2
  143. data/lib/active_support/time_with_zone.rb +60 -40
  144. data/lib/active_support/values/time_zone.rb +101 -101
  145. data/lib/active_support/values/unicode_tables.dat +0 -0
  146. data/lib/active_support/version.rb +4 -7
  147. data/lib/active_support/xml_mini/jdom.rb +6 -5
  148. data/lib/active_support/xml_mini/libxml.rb +1 -3
  149. data/lib/active_support/xml_mini/libxmlsax.rb +1 -4
  150. data/lib/active_support/xml_mini/nokogiri.rb +1 -3
  151. data/lib/active_support/xml_mini/nokogirisax.rb +1 -3
  152. data/lib/active_support/xml_mini/rexml.rb +7 -8
  153. data/lib/active_support/xml_mini.rb +33 -15
  154. data/lib/active_support.rb +27 -2
  155. metadata +43 -43
  156. data/lib/active_support/basic_object.rb +0 -11
  157. data/lib/active_support/buffered_logger.rb +0 -21
  158. data/lib/active_support/core_ext/array/uniq_by.rb +0 -19
  159. data/lib/active_support/core_ext/hash/diff.rb +0 -14
  160. data/lib/active_support/core_ext/logger.rb +0 -67
  161. data/lib/active_support/core_ext/object/to_json.rb +0 -27
  162. data/lib/active_support/core_ext/proc.rb +0 -17
  163. data/lib/active_support/core_ext/string/encoding.rb +0 -8
  164. data/lib/active_support/file_watcher.rb +0 -36
  165. data/lib/active_support/json/variable.rb +0 -18
  166. data/lib/active_support/testing/pending.rb +0 -14
@@ -1,338 +1,177 @@
1
- require 'active_support/core_ext/object/to_json'
1
+ require 'active_support/core_ext/object/json'
2
2
  require 'active_support/core_ext/module/delegation'
3
- require 'active_support/json/variable'
4
-
5
- require 'bigdecimal'
6
- require 'active_support/core_ext/big_decimal/conversions' # for #to_s
7
- require 'active_support/core_ext/hash/except'
8
- require 'active_support/core_ext/hash/slice'
9
- require 'active_support/core_ext/object/instance_variables'
10
- require 'time'
11
- require 'active_support/core_ext/time/conversions'
12
- require 'active_support/core_ext/date_time/conversions'
13
- require 'active_support/core_ext/date/conversions'
14
- require 'set'
3
+ require 'active_support/deprecation'
15
4
 
16
5
  module ActiveSupport
17
6
  class << self
18
7
  delegate :use_standard_json_time_format, :use_standard_json_time_format=,
8
+ :time_precision, :time_precision=,
19
9
  :escape_html_entities_in_json, :escape_html_entities_in_json=,
20
10
  :encode_big_decimal_as_string, :encode_big_decimal_as_string=,
11
+ :json_encoder, :json_encoder=,
21
12
  :to => :'ActiveSupport::JSON::Encoding'
22
13
  end
23
14
 
24
15
  module JSON
25
- # matches YAML-formatted dates
26
- DATE_REGEX = /^(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[T \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?))$/
27
-
28
16
  # Dumps objects in JSON (JavaScript Object Notation).
29
- # See www.json.org for more info.
17
+ # See http://www.json.org for more info.
30
18
  #
31
19
  # ActiveSupport::JSON.encode({ team: 'rails', players: '36' })
32
20
  # # => "{\"team\":\"rails\",\"players\":\"36\"}"
33
21
  def self.encode(value, options = nil)
34
- Encoding::Encoder.new(options).encode(value)
22
+ Encoding.json_encoder.new(options).encode(value)
35
23
  end
36
24
 
37
25
  module Encoding #:nodoc:
38
- class CircularReferenceError < StandardError; end
39
-
40
- class Encoder
26
+ class JSONGemEncoder #:nodoc:
41
27
  attr_reader :options
42
28
 
43
29
  def initialize(options = nil)
44
30
  @options = options || {}
45
- @seen = Set.new
46
31
  end
47
32
 
48
- def encode(value, use_options = true)
49
- check_for_circular_references(value) do
50
- jsonified = use_options ? value.as_json(options_for(value)) : value.as_json
51
- jsonified.encode_json(self)
52
- end
33
+ # Encode the given object into a JSON string
34
+ def encode(value)
35
+ stringify jsonify value.as_json(options.dup)
53
36
  end
54
37
 
55
- # like encode, but only calls as_json, without encoding to string.
56
- def as_json(value, use_options = true)
57
- check_for_circular_references(value) do
58
- use_options ? value.as_json(options_for(value)) : value.as_json
59
- end
60
- end
38
+ private
39
+ # Rails does more escaping than the JSON gem natively does (we
40
+ # escape \u2028 and \u2029 and optionally >, <, & to work around
41
+ # certain browser problems).
42
+ ESCAPED_CHARS = {
43
+ "\u2028" => '\u2028',
44
+ "\u2029" => '\u2029',
45
+ '>' => '\u003e',
46
+ '<' => '\u003c',
47
+ '&' => '\u0026',
48
+ }
49
+
50
+ ESCAPE_REGEX_WITH_HTML_ENTITIES = /[\u2028\u2029><&]/u
51
+ ESCAPE_REGEX_WITHOUT_HTML_ENTITIES = /[\u2028\u2029]/u
52
+
53
+ # This class wraps all the strings we see and does the extra escaping
54
+ class EscapedString < String #:nodoc:
55
+ def to_json(*)
56
+ if Encoding.escape_html_entities_in_json
57
+ super.gsub ESCAPE_REGEX_WITH_HTML_ENTITIES, ESCAPED_CHARS
58
+ else
59
+ super.gsub ESCAPE_REGEX_WITHOUT_HTML_ENTITIES, ESCAPED_CHARS
60
+ end
61
+ end
61
62
 
62
- def options_for(value)
63
- if value.is_a?(Array) || value.is_a?(Hash)
64
- # hashes and arrays need to get encoder in the options, so that
65
- # they can detect circular references.
66
- options.merge(:encoder => self)
67
- else
68
- options.dup
63
+ def to_s
64
+ self
65
+ end
69
66
  end
70
- end
71
67
 
72
- def escape(string)
73
- Encoding.escape(string)
74
- end
75
-
76
- private
77
- def check_for_circular_references(value)
78
- unless @seen.add?(value.__id__)
79
- raise CircularReferenceError, 'object references itself'
68
+ # Mark these as private so we don't leak encoding-specific constructs
69
+ private_constant :ESCAPED_CHARS, :ESCAPE_REGEX_WITH_HTML_ENTITIES,
70
+ :ESCAPE_REGEX_WITHOUT_HTML_ENTITIES, :EscapedString
71
+
72
+ # Convert an object into a "JSON-ready" representation composed of
73
+ # primitives like Hash, Array, String, Numeric, and true/false/nil.
74
+ # Recursively calls #as_json to the object to recursively build a
75
+ # fully JSON-ready object.
76
+ #
77
+ # This allows developers to implement #as_json without having to
78
+ # worry about what base types of objects they are allowed to return
79
+ # or having to remember to call #as_json recursively.
80
+ #
81
+ # Note: the +options+ hash passed to +object.to_json+ is only passed
82
+ # to +object.as_json+, not any of this method's recursive +#as_json+
83
+ # calls.
84
+ def jsonify(value)
85
+ case value
86
+ when String
87
+ EscapedString.new(value)
88
+ when Numeric, NilClass, TrueClass, FalseClass
89
+ value
90
+ when Hash
91
+ Hash[value.map { |k, v| [jsonify(k), jsonify(v)] }]
92
+ when Array
93
+ value.map { |v| jsonify(v) }
94
+ else
95
+ jsonify value.as_json
80
96
  end
81
- yield
82
- ensure
83
- @seen.delete(value.__id__)
84
97
  end
85
- end
86
98
 
87
-
88
- ESCAPED_CHARS = {
89
- "\x00" => '\u0000', "\x01" => '\u0001', "\x02" => '\u0002',
90
- "\x03" => '\u0003', "\x04" => '\u0004', "\x05" => '\u0005',
91
- "\x06" => '\u0006', "\x07" => '\u0007', "\x0B" => '\u000B',
92
- "\x0E" => '\u000E', "\x0F" => '\u000F', "\x10" => '\u0010',
93
- "\x11" => '\u0011', "\x12" => '\u0012', "\x13" => '\u0013',
94
- "\x14" => '\u0014', "\x15" => '\u0015', "\x16" => '\u0016',
95
- "\x17" => '\u0017', "\x18" => '\u0018', "\x19" => '\u0019',
96
- "\x1A" => '\u001A', "\x1B" => '\u001B', "\x1C" => '\u001C',
97
- "\x1D" => '\u001D', "\x1E" => '\u001E', "\x1F" => '\u001F',
98
- "\010" => '\b',
99
- "\f" => '\f',
100
- "\n" => '\n',
101
- "\r" => '\r',
102
- "\t" => '\t',
103
- '"' => '\"',
104
- '\\' => '\\\\',
105
- '>' => '\u003E',
106
- '<' => '\u003C',
107
- '&' => '\u0026' }
99
+ # Encode a "jsonified" Ruby data structure using the JSON gem
100
+ def stringify(jsonified)
101
+ ::JSON.generate(jsonified, quirks_mode: true, max_nesting: false)
102
+ end
103
+ end
108
104
 
109
105
  class << self
110
106
  # If true, use ISO 8601 format for dates and times. Otherwise, fall back
111
107
  # to the Active Support legacy format.
112
108
  attr_accessor :use_standard_json_time_format
113
109
 
114
- # If false, serializes BigDecimal objects as numeric instead of wrapping
115
- # them in a string.
116
- attr_accessor :encode_big_decimal_as_string
110
+ # If true, encode >, <, & as escaped unicode sequences (e.g. > as \u003e)
111
+ # as a safety measure.
112
+ attr_accessor :escape_html_entities_in_json
117
113
 
118
- attr_accessor :escape_regex
119
- attr_reader :escape_html_entities_in_json
114
+ # Sets the precision of encoded time values.
115
+ # Defaults to 3 (equivalent to millisecond precision)
116
+ attr_accessor :time_precision
120
117
 
121
- def escape_html_entities_in_json=(value)
122
- self.escape_regex = \
123
- if @escape_html_entities_in_json = value
124
- /[\x00-\x1F"\\><&]/
125
- else
126
- /[\x00-\x1F"\\]/
127
- end
128
- end
118
+ # Sets the encoder used by Rails to encode Ruby objects into JSON strings
119
+ # in +Object#to_json+ and +ActiveSupport::JSON.encode+.
120
+ attr_accessor :json_encoder
129
121
 
130
- def escape(string)
131
- string = string.encode(::Encoding::UTF_8, :undef => :replace).force_encoding(::Encoding::BINARY)
132
- json = string.gsub(escape_regex) { |s| ESCAPED_CHARS[s] }
133
- json = %("#{json}")
134
- json.force_encoding(::Encoding::UTF_8)
135
- json
136
- end
137
- end
122
+ def encode_big_decimal_as_string=(as_string)
123
+ message = \
124
+ "The JSON encoder in Rails 4.1 no longer supports encoding BigDecimals as JSON numbers. Instead, " \
125
+ "the new encoder will always encode them as strings.\n\n" \
126
+ "You are seeing this error because you have 'active_support.encode_big_decimal_as_string' in " \
127
+ "your configuration file. If you have been setting this to true, you can safely remove it from " \
128
+ "your configuration. Otherwise, you should add the 'activesupport-json_encoder' gem to your " \
129
+ "Gemfile in order to restore this functionality."
138
130
 
139
- self.use_standard_json_time_format = true
140
- self.escape_html_entities_in_json = true
141
- self.encode_big_decimal_as_string = true
142
- end
143
- end
144
- end
145
-
146
- class Object
147
- def as_json(options = nil) #:nodoc:
148
- if respond_to?(:to_hash)
149
- to_hash
150
- else
151
- instance_values
152
- end
153
- end
154
- end
155
-
156
- class Struct #:nodoc:
157
- def as_json(options = nil)
158
- Hash[members.zip(values)]
159
- end
160
- end
161
-
162
- class TrueClass
163
- def as_json(options = nil) #:nodoc:
164
- self
165
- end
166
-
167
- def encode_json(encoder) #:nodoc:
168
- to_s
169
- end
170
- end
171
-
172
- class FalseClass
173
- def as_json(options = nil) #:nodoc:
174
- self
175
- end
176
-
177
- def encode_json(encoder) #:nodoc:
178
- to_s
179
- end
180
- end
181
-
182
- class NilClass
183
- def as_json(options = nil) #:nodoc:
184
- self
185
- end
186
-
187
- def encode_json(encoder) #:nodoc:
188
- 'null'
189
- end
190
- end
191
-
192
- class String
193
- def as_json(options = nil) #:nodoc:
194
- self
195
- end
196
-
197
- def encode_json(encoder) #:nodoc:
198
- encoder.escape(self)
199
- end
200
- end
201
-
202
- class Symbol
203
- def as_json(options = nil) #:nodoc:
204
- to_s
205
- end
206
- end
207
-
208
- class Numeric
209
- def as_json(options = nil) #:nodoc:
210
- self
211
- end
212
-
213
- def encode_json(encoder) #:nodoc:
214
- to_s
215
- end
216
- end
217
-
218
- class Float
219
- # Encoding Infinity or NaN to JSON should return "null". The default returns
220
- # "Infinity" or "NaN" which breaks parsing the JSON. E.g. JSON.parse('[NaN]').
221
- def as_json(options = nil) #:nodoc:
222
- finite? ? self : nil
223
- end
224
- end
225
-
226
- class BigDecimal
227
- # A BigDecimal would be naturally represented as a JSON number. Most libraries,
228
- # however, parse non-integer JSON numbers directly as floats. Clients using
229
- # those libraries would get in general a wrong number and no way to recover
230
- # other than manually inspecting the string with the JSON code itself.
231
- #
232
- # That's why a JSON string is returned. The JSON literal is not numeric, but
233
- # if the other end knows by contract that the data is supposed to be a
234
- # BigDecimal, it still has the chance to post-process the string and get the
235
- # real value.
236
- #
237
- # Use <tt>ActiveSupport.encode_big_decimal_as_string = true</tt> to
238
- # override this behavior.
239
- def as_json(options = nil) #:nodoc:
240
- if finite?
241
- ActiveSupport.encode_big_decimal_as_string ? to_s : self
242
- else
243
- nil
244
- end
245
- end
246
- end
247
-
248
- class Regexp
249
- def as_json(options = nil) #:nodoc:
250
- to_s
251
- end
252
- end
253
-
254
- module Enumerable
255
- def as_json(options = nil) #:nodoc:
256
- to_a.as_json(options)
257
- end
258
- end
131
+ raise NotImplementedError, message
132
+ end
259
133
 
260
- class Range
261
- def as_json(options = nil) #:nodoc:
262
- to_s
263
- end
264
- end
134
+ def encode_big_decimal_as_string
135
+ message = \
136
+ "The JSON encoder in Rails 4.1 no longer supports encoding BigDecimals as JSON numbers. Instead, " \
137
+ "the new encoder will always encode them as strings.\n\n" \
138
+ "You are seeing this error because you are trying to check the value of the related configuration, " \
139
+ "`active_support.encode_big_decimal_as_string`. If your application depends on this option, you should " \
140
+ "add the 'activesupport-json_encoder' gem to your Gemfile. For now, this option will always be true. " \
141
+ "In the future, it will be removed from Rails, so you should stop checking its value."
265
142
 
266
- class Array
267
- def as_json(options = nil) #:nodoc:
268
- # use encoder as a proxy to call as_json on all elements, to protect from circular references
269
- encoder = options && options[:encoder] || ActiveSupport::JSON::Encoding::Encoder.new(options)
270
- map { |v| encoder.as_json(v, options) }
271
- end
143
+ ActiveSupport::Deprecation.warn message
272
144
 
273
- def encode_json(encoder) #:nodoc:
274
- # we assume here that the encoder has already run as_json on self and the elements, so we run encode_json directly
275
- "[#{map { |v| v.encode_json(encoder) } * ','}]"
276
- end
277
- end
145
+ true
146
+ end
278
147
 
279
- class Hash
280
- def as_json(options = nil) #:nodoc:
281
- # create a subset of the hash by applying :only or :except
282
- subset = if options
283
- if attrs = options[:only]
284
- slice(*Array(attrs))
285
- elsif attrs = options[:except]
286
- except(*Array(attrs))
287
- else
288
- self
148
+ # Deprecate CircularReferenceError
149
+ def const_missing(name)
150
+ if name == :CircularReferenceError
151
+ message = "The JSON encoder in Rails 4.1 no longer offers protection from circular references. " \
152
+ "You are seeing this warning because you are rescuing from (or otherwise referencing) " \
153
+ "ActiveSupport::Encoding::CircularReferenceError. In the future, this error will be " \
154
+ "removed from Rails. You should remove these rescue blocks from your code and ensure " \
155
+ "that your data structures are free of circular references so they can be properly " \
156
+ "serialized into JSON.\n\n" \
157
+ "For example, the following Hash contains a circular reference to itself:\n" \
158
+ " h = {}\n" \
159
+ " h['circular'] = h\n" \
160
+ "In this case, calling h.to_json would not work properly."
161
+
162
+ ActiveSupport::Deprecation.warn message
163
+
164
+ SystemStackError
165
+ else
166
+ super
167
+ end
168
+ end
289
169
  end
290
- else
291
- self
292
- end
293
-
294
- # use encoder as a proxy to call as_json on all values in the subset, to protect from circular references
295
- encoder = options && options[:encoder] || ActiveSupport::JSON::Encoding::Encoder.new(options)
296
- Hash[subset.map { |k, v| [k.to_s, encoder.as_json(v, options)] }]
297
- end
298
-
299
- def encode_json(encoder) #:nodoc:
300
- # values are encoded with use_options = false, because we don't want hash representations from ActiveModel to be
301
- # processed once again with as_json with options, as this could cause unexpected results (i.e. missing fields);
302
-
303
- # on the other hand, we need to run as_json on the elements, because the model representation may contain fields
304
- # like Time/Date in their original (not jsonified) form, etc.
305
170
 
306
- "{#{map { |k,v| "#{encoder.encode(k.to_s)}:#{encoder.encode(v, false)}" } * ','}}"
307
- end
308
- end
309
-
310
- class Time
311
- def as_json(options = nil) #:nodoc:
312
- if ActiveSupport.use_standard_json_time_format
313
- xmlschema
314
- else
315
- %(#{strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)})
316
- end
317
- end
318
- end
319
-
320
- class Date
321
- def as_json(options = nil) #:nodoc:
322
- if ActiveSupport.use_standard_json_time_format
323
- strftime("%Y-%m-%d")
324
- else
325
- strftime("%Y/%m/%d")
326
- end
327
- end
328
- end
329
-
330
- class DateTime
331
- def as_json(options = nil) #:nodoc:
332
- if ActiveSupport.use_standard_json_time_format
333
- xmlschema
334
- else
335
- strftime('%Y/%m/%d %H:%M:%S %z')
171
+ self.use_standard_json_time_format = true
172
+ self.escape_html_entities_in_json = true
173
+ self.json_encoder = JSONGemEncoder
174
+ self.time_precision = 3
336
175
  end
337
176
  end
338
177
  end
@@ -4,7 +4,7 @@ require 'openssl'
4
4
  module ActiveSupport
5
5
  # KeyGenerator is a simple wrapper around OpenSSL's implementation of PBKDF2
6
6
  # It can be used to derive a number of keys for various purposes from a given secret.
7
- # This lets rails applications have a single secure secret, but avoid reusing that
7
+ # This lets Rails applications have a single secure secret, but avoid reusing that
8
8
  # key in multiple incompatible contexts.
9
9
  class KeyGenerator
10
10
  def initialize(secret, options = {})
@@ -57,18 +57,16 @@ module ActiveSupport
57
57
  # secret they've provided is at least 30 characters in length.
58
58
  def ensure_secret_secure(secret)
59
59
  if secret.blank?
60
- raise ArgumentError, "A secret is required to generate an " +
61
- "integrity hash for cookie session data. Use " +
62
- "config.secret_key_base = \"some secret phrase of at " +
63
- "least #{SECRET_MIN_LENGTH} characters\"" +
64
- "in config/initializers/secret_token.rb"
60
+ raise ArgumentError, "A secret is required to generate an integrity hash " \
61
+ "for cookie session data. Set a secret_key_base of at least " \
62
+ "#{SECRET_MIN_LENGTH} characters in config/secrets.yml."
65
63
  end
66
64
 
67
65
  if secret.length < SECRET_MIN_LENGTH
68
- raise ArgumentError, "Secret should be something secure, " +
69
- "like \"#{SecureRandom.hex(16)}\". The value you " +
70
- "provided, \"#{secret}\", is shorter than the minimum length " +
71
- "of #{SECRET_MIN_LENGTH} characters"
66
+ raise ArgumentError, "Secret should be something secure, " \
67
+ "like \"#{SecureRandom.hex(16)}\". The value you " \
68
+ "provided, \"#{secret}\", is shorter than the minimum length " \
69
+ "of #{SECRET_MIN_LENGTH} characters."
72
70
  end
73
71
  end
74
72
  end
@@ -1,5 +1,5 @@
1
1
  module ActiveSupport
2
- # lazy_load_hooks allows rails to lazily load a lot of components and thus
2
+ # lazy_load_hooks allows Rails to lazily load a lot of components and thus
3
3
  # making the app boot faster. Because of this feature now there is no need to
4
4
  # require <tt>ActiveRecord::Base</tt> at boot time purely to apply
5
5
  # configuration. Instead a hook is registered that applies configuration once
@@ -1,5 +1,5 @@
1
1
  require 'active_support/log_subscriber'
2
- require 'active_support/buffered_logger'
2
+ require 'active_support/logger'
3
3
  require 'active_support/notifications'
4
4
 
5
5
  module ActiveSupport
@@ -1,11 +1,24 @@
1
- require 'active_support/core_ext/class/attribute_accessors'
1
+ require 'active_support/core_ext/module/attribute_accessors'
2
2
  require 'active_support/logger_silence'
3
+ require 'active_support/logger_thread_safe_level'
3
4
  require 'logger'
4
5
 
5
6
  module ActiveSupport
6
7
  class Logger < ::Logger
8
+ include ActiveSupport::LoggerThreadSafeLevel
7
9
  include LoggerSilence
8
10
 
11
+ # Returns true if the logger destination matches one of the sources
12
+ #
13
+ # logger = Logger.new(STDOUT)
14
+ # ActiveSupport::Logger.logger_outputs_to?(logger, STDOUT)
15
+ # # => true
16
+ def self.logger_outputs_to?(logger, *sources)
17
+ logdev = logger.instance_variable_get("@logdev")
18
+ logger_source = logdev.dev if logdev.respond_to?(:dev)
19
+ sources.any? { |source| source == logger_source }
20
+ end
21
+
9
22
  # Broadcasts logs to multiple loggers.
10
23
  def self.broadcast(logger) # :nodoc:
11
24
  Module.new do
@@ -38,12 +51,49 @@ module ActiveSupport
38
51
  logger.level = level
39
52
  super(level)
40
53
  end
54
+
55
+ define_method(:local_level=) do |level|
56
+ logger.local_level = level if logger.respond_to?(:local_level=)
57
+ super(level) if respond_to?(:local_level=)
58
+ end
59
+
60
+ define_method(:silence) do |level = Logger::ERROR, &block|
61
+ if logger.respond_to?(:silence) && logger.method(:silence).owner != ::Kernel
62
+ logger.silence(level) do
63
+ if respond_to?(:silence) && method(:silence).owner != ::Kernel
64
+ super(level, &block)
65
+ else
66
+ block.call(self)
67
+ end
68
+ end
69
+ else
70
+ if respond_to?(:silence) && method(:silence).owner != ::Kernel
71
+ super(level, &block)
72
+ else
73
+ block.call(self)
74
+ end
75
+ end
76
+ end
41
77
  end
42
78
  end
43
79
 
44
80
  def initialize(*args)
45
81
  super
46
82
  @formatter = SimpleFormatter.new
83
+ after_initialize if respond_to? :after_initialize
84
+ end
85
+
86
+ def add(severity, message = nil, progname = nil, &block)
87
+ return true if @logdev.nil? || (severity || UNKNOWN) < level
88
+ super
89
+ end
90
+
91
+ Logger::Severity.constants.each do |severity|
92
+ class_eval(<<-EOT, __FILE__, __LINE__ + 1)
93
+ def #{severity.downcase}? # def debug?
94
+ Logger::#{severity} >= level # DEBUG >= level
95
+ end # end
96
+ EOT
47
97
  end
48
98
 
49
99
  # Simple formatter which only displays the message.
@@ -1,8 +1,9 @@
1
1
  require 'active_support/concern'
2
+ require 'thread_safe'
2
3
 
3
4
  module LoggerSilence
4
5
  extend ActiveSupport::Concern
5
-
6
+
6
7
  included do
7
8
  cattr_accessor :silencer
8
9
  self.silencer = true
@@ -12,13 +13,15 @@ module LoggerSilence
12
13
  def silence(temporary_level = Logger::ERROR)
13
14
  if silencer
14
15
  begin
15
- old_logger_level, self.level = level, temporary_level
16
+ old_local_level = local_level
17
+ self.local_level = temporary_level
18
+
16
19
  yield self
17
20
  ensure
18
- self.level = old_logger_level
21
+ self.local_level = old_local_level
19
22
  end
20
23
  else
21
24
  yield self
22
25
  end
23
26
  end
24
- end
27
+ end
@@ -0,0 +1,32 @@
1
+ require 'active_support/concern'
2
+ require 'thread_safe'
3
+
4
+ module ActiveSupport
5
+ module LoggerThreadSafeLevel
6
+ extend ActiveSupport::Concern
7
+
8
+ def after_initialize
9
+ @local_levels = ThreadSafe::Cache.new
10
+ end
11
+
12
+ def local_log_id
13
+ Thread.current.__id__
14
+ end
15
+
16
+ def local_level
17
+ @local_levels[local_log_id]
18
+ end
19
+
20
+ def local_level=(level)
21
+ if level
22
+ @local_levels[local_log_id] = level
23
+ else
24
+ @local_levels.delete(local_log_id)
25
+ end
26
+ end
27
+
28
+ def level
29
+ local_level || super
30
+ end
31
+ end
32
+ end