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,7 +1,7 @@
1
1
  #--
2
- # Most objects are cloneable, but not all. For example you can't dup +nil+:
2
+ # Most objects are cloneable, but not all. For example you can't dup methods:
3
3
  #
4
- # nil.dup # => TypeError: can't dup NilClass
4
+ # method(:puts).dup # => TypeError: allocator undefined for Method
5
5
  #
6
6
  # Classes may signal their instances are not duplicable removing +dup+/+clone+
7
7
  # or raising exceptions from them. So, to dup an arbitrary object you normally
@@ -19,7 +19,7 @@
19
19
  class Object
20
20
  # Can you safely dup this object?
21
21
  #
22
- # False for +nil+, +false+, +true+, symbol, and number objects;
22
+ # False for +nil+, +false+, +true+, symbol, number and BigDecimal(in 1.9.x) objects;
23
23
  # true otherwise.
24
24
  def duplicable?
25
25
  true
@@ -27,57 +27,86 @@ class Object
27
27
  end
28
28
 
29
29
  class NilClass
30
- # +nil+ is not duplicable:
31
- #
32
- # nil.duplicable? # => false
33
- # nil.dup # => TypeError: can't dup NilClass
34
- def duplicable?
35
- false
30
+ begin
31
+ nil.dup
32
+ rescue TypeError
33
+
34
+ # +nil+ is not duplicable:
35
+ #
36
+ # nil.duplicable? # => false
37
+ # nil.dup # => TypeError: can't dup NilClass
38
+ def duplicable?
39
+ false
40
+ end
36
41
  end
37
42
  end
38
43
 
39
44
  class FalseClass
40
- # +false+ is not duplicable:
41
- #
42
- # false.duplicable? # => false
43
- # false.dup # => TypeError: can't dup FalseClass
44
- def duplicable?
45
- false
45
+ begin
46
+ false.dup
47
+ rescue TypeError
48
+
49
+ # +false+ is not duplicable:
50
+ #
51
+ # false.duplicable? # => false
52
+ # false.dup # => TypeError: can't dup FalseClass
53
+ def duplicable?
54
+ false
55
+ end
46
56
  end
47
57
  end
48
58
 
49
59
  class TrueClass
50
- # +true+ is not duplicable:
51
- #
52
- # true.duplicable? # => false
53
- # true.dup # => TypeError: can't dup TrueClass
54
- def duplicable?
55
- false
60
+ begin
61
+ true.dup
62
+ rescue TypeError
63
+
64
+ # +true+ is not duplicable:
65
+ #
66
+ # true.duplicable? # => false
67
+ # true.dup # => TypeError: can't dup TrueClass
68
+ def duplicable?
69
+ false
70
+ end
56
71
  end
57
72
  end
58
73
 
59
74
  class Symbol
60
- # Symbols are not duplicable:
61
- #
62
- # :my_symbol.duplicable? # => false
63
- # :my_symbol.dup # => TypeError: can't dup Symbol
64
- def duplicable?
65
- false
75
+ begin
76
+ :symbol.dup # Ruby 2.4.x.
77
+ 'symbol_from_string'.to_sym.dup # Some symbols can't `dup` in Ruby 2.4.0.
78
+ rescue TypeError
79
+
80
+ # Symbols are not duplicable:
81
+ #
82
+ # :my_symbol.duplicable? # => false
83
+ # :my_symbol.dup # => TypeError: can't dup Symbol
84
+ def duplicable?
85
+ false
86
+ end
66
87
  end
67
88
  end
68
89
 
69
90
  class Numeric
70
- # Numbers are not duplicable:
71
- #
72
- # 3.duplicable? # => false
73
- # 3.dup # => TypeError: can't dup Fixnum
74
- def duplicable?
75
- false
91
+ begin
92
+ 1.dup
93
+ rescue TypeError
94
+
95
+ # Numbers are not duplicable:
96
+ #
97
+ # 3.duplicable? # => false
98
+ # 3.dup # => TypeError: can't dup Integer
99
+ def duplicable?
100
+ false
101
+ end
76
102
  end
77
103
  end
78
104
 
79
105
  require 'bigdecimal'
80
106
  class BigDecimal
107
+ # Needed to support Ruby 1.9.x, as it doesn't allow dup on BigDecimal, instead
108
+ # raises TypeError exception. Checking here on the runtime whether BigDecimal
109
+ # will allow dup or not.
81
110
  begin
82
111
  BigDecimal.new('4.56').dup
83
112
 
@@ -88,3 +117,13 @@ class BigDecimal
88
117
  # can't dup, so use superclass implementation
89
118
  end
90
119
  end
120
+
121
+ class Method
122
+ # Methods are not duplicable:
123
+ #
124
+ # method(:puts).duplicable? # => false
125
+ # method(:puts).dup # => TypeError: allocator undefined for Method
126
+ def duplicable?
127
+ false
128
+ end
129
+ end
@@ -1,5 +1,3 @@
1
- require 'active_support/deprecation'
2
-
3
1
  class Object
4
2
  # Returns true if this object is included in the argument. Argument must be
5
3
  # any object which responds to +#include?+. Usage:
@@ -9,18 +7,21 @@ class Object
9
7
  #
10
8
  # This will throw an ArgumentError if the argument doesn't respond
11
9
  # to +#include?+.
12
- def in?(*args)
13
- if args.length > 1
14
- ActiveSupport::Deprecation.warn "Calling #in? with multiple arguments is" \
15
- " deprecated, please pass in an object that responds to #include? instead."
16
- args.include? self
17
- else
18
- another_object = args.first
19
- if another_object.respond_to? :include?
20
- another_object.include? self
21
- else
22
- raise ArgumentError.new 'The single parameter passed to #in? must respond to #include?'
23
- end
24
- end
10
+ def in?(another_object)
11
+ another_object.include?(self)
12
+ rescue NoMethodError
13
+ raise ArgumentError.new("The parameter passed to #in? must respond to #include?")
14
+ end
15
+
16
+ # Returns the receiver if it's included in the argument otherwise returns +nil+.
17
+ # Argument must be any object which responds to +#include?+. Usage:
18
+ #
19
+ # params[:bucket_type].presence_in %w( project calendar )
20
+ #
21
+ # This will throw an ArgumentError if the argument doesn't respond to +#include?+.
22
+ #
23
+ # @return [Object]
24
+ def presence_in(another_object)
25
+ self.in?(another_object) ? self : nil
25
26
  end
26
27
  end
@@ -0,0 +1,15 @@
1
+ class Object
2
+ # TODO: Remove this file when we drop support for Ruby < 2.2
3
+ unless respond_to?(:itself)
4
+ # Returns the object itself.
5
+ #
6
+ # Useful for chaining methods, such as Active Record scopes:
7
+ #
8
+ # Event.public_send(state.presence_in([ :trashed, :drafted ]) || :itself).order(:created_at)
9
+ #
10
+ # @return Object
11
+ def itself
12
+ self
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,197 @@
1
+ # Hack to load json gem first so we can overwrite its to_json.
2
+ require 'json'
3
+ require 'bigdecimal'
4
+ require 'active_support/core_ext/big_decimal/conversions' # for #to_s
5
+ require 'active_support/core_ext/hash/except'
6
+ require 'active_support/core_ext/hash/slice'
7
+ require 'active_support/core_ext/object/instance_variables'
8
+ require 'time'
9
+ require 'active_support/core_ext/time/conversions'
10
+ require 'active_support/core_ext/date_time/conversions'
11
+ require 'active_support/core_ext/date/conversions'
12
+ require 'active_support/core_ext/module/aliasing'
13
+
14
+ # The JSON gem adds a few modules to Ruby core classes containing :to_json definition, overwriting
15
+ # their default behavior. That said, we need to define the basic to_json method in all of them,
16
+ # otherwise they will always use to_json gem implementation, which is backwards incompatible in
17
+ # several cases (for instance, the JSON implementation for Hash does not work) with inheritance
18
+ # and consequently classes as ActiveSupport::OrderedHash cannot be serialized to json.
19
+ #
20
+ # On the other hand, we should avoid conflict with ::JSON.{generate,dump}(obj). Unfortunately, the
21
+ # JSON gem's encoder relies on its own to_json implementation to encode objects. Since it always
22
+ # passes a ::JSON::State object as the only argument to to_json, we can detect that and forward the
23
+ # calls to the original to_json method.
24
+ #
25
+ # It should be noted that when using ::JSON.{generate,dump} directly, ActiveSupport's encoder is
26
+ # bypassed completely. This means that as_json won't be invoked and the JSON gem will simply
27
+ # ignore any options it does not natively understand. This also means that ::JSON.{generate,dump}
28
+ # should give exactly the same results with or without active support.
29
+ [Enumerable, Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass].each do |klass|
30
+ klass.class_eval do
31
+ def to_json_with_active_support_encoder(options = nil) # :nodoc:
32
+ if options.is_a?(::JSON::State)
33
+ # Called from JSON.{generate,dump}, forward it to JSON gem's to_json
34
+ self.to_json_without_active_support_encoder(options)
35
+ else
36
+ # to_json is being invoked directly, use ActiveSupport's encoder
37
+ ActiveSupport::JSON.encode(self, options)
38
+ end
39
+ end
40
+
41
+ alias_method_chain :to_json, :active_support_encoder
42
+ end
43
+ end
44
+
45
+ class Object
46
+ def as_json(options = nil) #:nodoc:
47
+ if respond_to?(:to_hash)
48
+ to_hash.as_json(options)
49
+ else
50
+ instance_values.as_json(options)
51
+ end
52
+ end
53
+ end
54
+
55
+ class Struct #:nodoc:
56
+ def as_json(options = nil)
57
+ Hash[members.zip(values)].as_json(options)
58
+ end
59
+ end
60
+
61
+ class TrueClass
62
+ def as_json(options = nil) #:nodoc:
63
+ self
64
+ end
65
+ end
66
+
67
+ class FalseClass
68
+ def as_json(options = nil) #:nodoc:
69
+ self
70
+ end
71
+ end
72
+
73
+ class NilClass
74
+ def as_json(options = nil) #:nodoc:
75
+ self
76
+ end
77
+ end
78
+
79
+ class String
80
+ def as_json(options = nil) #:nodoc:
81
+ self
82
+ end
83
+ end
84
+
85
+ class Symbol
86
+ def as_json(options = nil) #:nodoc:
87
+ to_s
88
+ end
89
+ end
90
+
91
+ class Numeric
92
+ def as_json(options = nil) #:nodoc:
93
+ self
94
+ end
95
+ end
96
+
97
+ class Float
98
+ # Encoding Infinity or NaN to JSON should return "null". The default returns
99
+ # "Infinity" or "NaN" which are not valid JSON.
100
+ def as_json(options = nil) #:nodoc:
101
+ finite? ? self : nil
102
+ end
103
+ end
104
+
105
+ class BigDecimal
106
+ # A BigDecimal would be naturally represented as a JSON number. Most libraries,
107
+ # however, parse non-integer JSON numbers directly as floats. Clients using
108
+ # those libraries would get in general a wrong number and no way to recover
109
+ # other than manually inspecting the string with the JSON code itself.
110
+ #
111
+ # That's why a JSON string is returned. The JSON literal is not numeric, but
112
+ # if the other end knows by contract that the data is supposed to be a
113
+ # BigDecimal, it still has the chance to post-process the string and get the
114
+ # real value.
115
+ def as_json(options = nil) #:nodoc:
116
+ finite? ? to_s : nil
117
+ end
118
+ end
119
+
120
+ class Regexp
121
+ def as_json(options = nil) #:nodoc:
122
+ to_s
123
+ end
124
+ end
125
+
126
+ module Enumerable
127
+ def as_json(options = nil) #:nodoc:
128
+ to_a.as_json(options)
129
+ end
130
+ end
131
+
132
+ class Range
133
+ def as_json(options = nil) #:nodoc:
134
+ to_s
135
+ end
136
+ end
137
+
138
+ class Array
139
+ def as_json(options = nil) #:nodoc:
140
+ map { |v| options ? v.as_json(options.dup) : v.as_json }
141
+ end
142
+ end
143
+
144
+ class Hash
145
+ def as_json(options = nil) #:nodoc:
146
+ # create a subset of the hash by applying :only or :except
147
+ subset = if options
148
+ if attrs = options[:only]
149
+ slice(*Array(attrs))
150
+ elsif attrs = options[:except]
151
+ except(*Array(attrs))
152
+ else
153
+ self
154
+ end
155
+ else
156
+ self
157
+ end
158
+
159
+ Hash[subset.map { |k, v| [k.to_s, options ? v.as_json(options.dup) : v.as_json] }]
160
+ end
161
+ end
162
+
163
+ class Time
164
+ def as_json(options = nil) #:nodoc:
165
+ if ActiveSupport::JSON::Encoding.use_standard_json_time_format
166
+ xmlschema(ActiveSupport::JSON::Encoding.time_precision)
167
+ else
168
+ %(#{strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)})
169
+ end
170
+ end
171
+ end
172
+
173
+ class Date
174
+ def as_json(options = nil) #:nodoc:
175
+ if ActiveSupport::JSON::Encoding.use_standard_json_time_format
176
+ strftime("%Y-%m-%d")
177
+ else
178
+ strftime("%Y/%m/%d")
179
+ end
180
+ end
181
+ end
182
+
183
+ class DateTime
184
+ def as_json(options = nil) #:nodoc:
185
+ if ActiveSupport::JSON::Encoding.use_standard_json_time_format
186
+ xmlschema(ActiveSupport::JSON::Encoding.time_precision)
187
+ else
188
+ strftime('%Y/%m/%d %H:%M:%S %z')
189
+ end
190
+ end
191
+ end
192
+
193
+ class Process::Status #:nodoc:
194
+ def as_json(options = nil)
195
+ { :exitstatus => exitstatus, :pid => pid }
196
+ end
197
+ end
@@ -1,3 +1,5 @@
1
+ require 'cgi'
2
+
1
3
  class Object
2
4
  # Alias of <tt>to_s</tt>.
3
5
  def to_param
@@ -7,7 +9,6 @@ class Object
7
9
  # Converts an object into a string suitable for use as a URL query string,
8
10
  # using the given <tt>key</tt> as the param name.
9
11
  def to_query(key)
10
- require 'cgi' unless defined?(CGI) && defined?(CGI::escape)
11
12
  "#{CGI.escape(key.to_param)}=#{CGI.escape(to_param.to_s)}"
12
13
  end
13
14
  end
@@ -46,7 +47,12 @@ class Array
46
47
  # ['Rails', 'coding'].to_query('hobbies') # => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding"
47
48
  def to_query(key)
48
49
  prefix = "#{key}[]"
49
- collect { |value| value.to_query(prefix) }.join '&'
50
+
51
+ if empty?
52
+ nil.to_query(prefix)
53
+ else
54
+ collect { |value| value.to_query(prefix) }.join '&'
55
+ end
50
56
  end
51
57
  end
52
58
 
@@ -57,10 +63,10 @@ class Hash
57
63
  # {name: 'David', nationality: 'Danish'}.to_query
58
64
  # # => "name=David&nationality=Danish"
59
65
  #
60
- # An optional namespace can be passed to enclose the param names:
66
+ # An optional namespace can be passed to enclose key names:
61
67
  #
62
68
  # {name: 'David', nationality: 'Danish'}.to_query('user')
63
- # # => "user[name]=David&user[nationality]=Danish"
69
+ # # => "user%5Bname%5D=David&user%5Bnationality%5D=Danish"
64
70
  #
65
71
  # The string pairs "key=value" that conform the query string
66
72
  # are sorted lexicographically in ascending order.
@@ -68,8 +74,10 @@ class Hash
68
74
  # This method is also aliased as +to_param+.
69
75
  def to_query(namespace = nil)
70
76
  collect do |key, value|
71
- value.to_query(namespace ? "#{namespace}[#{key}]" : key)
72
- end.sort * '&'
77
+ unless (value.is_a?(Hash) || value.is_a?(Array)) && value.empty?
78
+ value.to_query(namespace ? "#{namespace}[#{key}]" : key)
79
+ end
80
+ end.compact.sort! * '&'
73
81
  end
74
82
 
75
83
  alias_method :to_param, :to_query
@@ -9,7 +9,23 @@ class Object
9
9
  #
10
10
  # instead of
11
11
  #
12
- # @person ? @person.name : nil
12
+ # @person.name if @person
13
+ #
14
+ # +try+ calls can be chained:
15
+ #
16
+ # @person.try(:spouse).try(:name)
17
+ #
18
+ # instead of
19
+ #
20
+ # @person.spouse.name if @person && @person.spouse
21
+ #
22
+ # +try+ will also return +nil+ if the receiver does not respond to the method:
23
+ #
24
+ # @person.try(:non_existing_method) #=> nil
25
+ #
26
+ # instead of
27
+ #
28
+ # @person.non_existing_method if @person.respond_to?(:non_existing_method) #=> nil
13
29
  #
14
30
  # +try+ returns +nil+ when called on +nil+ regardless of whether it responds
15
31
  # to the method:
@@ -24,7 +40,7 @@ class Object
24
40
  #
25
41
  # The number of arguments in the signature must match. If the object responds
26
42
  # to the method the call is attempted and +ArgumentError+ is still raised
27
- # otherwise.
43
+ # in case of argument mismatch.
28
44
  #
29
45
  # If +try+ is called without arguments it yields the receiver to a given
30
46
  # block unless it is +nil+:
@@ -33,24 +49,30 @@ class Object
33
49
  # ...
34
50
  # end
35
51
  #
36
- # Please also note that +try+ is defined on +Object+, therefore it won't work
52
+ # You can also call try with a block without accepting an argument, and the block
53
+ # will be instance_eval'ed instead:
54
+ #
55
+ # @person.try { upcase.truncate(50) }
56
+ #
57
+ # Please also note that +try+ is defined on +Object+. Therefore, it won't work
37
58
  # with instances of classes that do not have +Object+ among their ancestors,
38
59
  # like direct subclasses of +BasicObject+. For example, using +try+ with
39
60
  # +SimpleDelegator+ will delegate +try+ to the target instead of calling it on
40
- # delegator itself.
61
+ # the delegator itself.
41
62
  def try(*a, &b)
42
- if a.empty? && block_given?
43
- yield self
44
- else
45
- public_send(*a, &b) if respond_to?(a.first)
46
- end
63
+ try!(*a, &b) if a.empty? || respond_to?(a.first)
47
64
  end
48
65
 
49
- # Same as #try, but will raise a NoMethodError exception if the receiving is not nil and
50
- # does not implemented the tried method.
66
+ # Same as #try, but will raise a NoMethodError exception if the receiver is not +nil+ and
67
+ # does not implement the tried method.
68
+
51
69
  def try!(*a, &b)
52
70
  if a.empty? && block_given?
53
- yield self
71
+ if b.arity == 0
72
+ instance_eval(&b)
73
+ else
74
+ yield self
75
+ end
54
76
  else
55
77
  public_send(*a, &b)
56
78
  end
@@ -59,12 +81,12 @@ end
59
81
 
60
82
  class NilClass
61
83
  # Calling +try+ on +nil+ always returns +nil+.
62
- # It becomes specially helpful when navigating through associations that may return +nil+.
84
+ # It becomes especially helpful when navigating through associations that may return +nil+.
63
85
  #
64
86
  # nil.try(:name) # => nil
65
87
  #
66
88
  # Without +try+
67
- # @person && !@person.children.blank? && @person.children.first.name
89
+ # @person && @person.children.any? && @person.children.first.name
68
90
  #
69
91
  # With +try+
70
92
  # @person.try(:children).try(:first).try(:name)
@@ -34,9 +34,36 @@ class Object
34
34
  # body i18n.t :body, user_name: user.name
35
35
  # end
36
36
  #
37
+ # When you don't pass an explicit receiver, it executes the whole block
38
+ # in merging options context:
39
+ #
40
+ # class Account < ActiveRecord::Base
41
+ # with_options dependent: :destroy do
42
+ # has_many :customers
43
+ # has_many :products
44
+ # has_many :invoices
45
+ # has_many :expenses
46
+ # end
47
+ # end
48
+ #
37
49
  # <tt>with_options</tt> can also be nested since the call is forwarded to its receiver.
38
- # Each nesting level will merge inherited defaults in addition to their own.
39
- def with_options(options)
40
- yield ActiveSupport::OptionMerger.new(self, options)
50
+ #
51
+ # NOTE: Each nesting level will merge inherited defaults in addition to their own.
52
+ #
53
+ # class Post < ActiveRecord::Base
54
+ # with_options if: :persisted?, length: { minimum: 50 } do
55
+ # validates :content, if: -> { content.present? }
56
+ # end
57
+ # end
58
+ #
59
+ # The code is equivalent to:
60
+ #
61
+ # validates :content, length: { minimum: 50 }, if: -> { content.present? }
62
+ #
63
+ # Hence the inherited default for `if` key is ignored.
64
+ #
65
+ def with_options(options, &block)
66
+ option_merger = ActiveSupport::OptionMerger.new(self, options)
67
+ block.arity.zero? ? option_merger.instance_eval(&block) : block.call(option_merger)
41
68
  end
42
69
  end
@@ -2,13 +2,14 @@ require 'active_support/core_ext/object/acts_like'
2
2
  require 'active_support/core_ext/object/blank'
3
3
  require 'active_support/core_ext/object/duplicable'
4
4
  require 'active_support/core_ext/object/deep_dup'
5
+ require 'active_support/core_ext/object/itself'
5
6
  require 'active_support/core_ext/object/try'
6
7
  require 'active_support/core_ext/object/inclusion'
7
8
 
8
9
  require 'active_support/core_ext/object/conversions'
9
10
  require 'active_support/core_ext/object/instance_variables'
10
11
 
11
- require 'active_support/core_ext/object/to_json'
12
+ require 'active_support/core_ext/object/json'
12
13
  require 'active_support/core_ext/object/to_param'
13
14
  require 'active_support/core_ext/object/to_query'
14
15
  require 'active_support/core_ext/object/with_options'