activesupport 4.2.0 → 5.0.0

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 (185) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +630 -220
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +2 -3
  5. data/lib/active_support/array_inquirer.rb +44 -0
  6. data/lib/active_support/backtrace_cleaner.rb +1 -1
  7. data/lib/active_support/benchmarkable.rb +1 -1
  8. data/lib/active_support/cache/file_store.rb +36 -22
  9. data/lib/active_support/cache/mem_cache_store.rb +63 -54
  10. data/lib/active_support/cache/memory_store.rb +16 -21
  11. data/lib/active_support/cache/null_store.rb +1 -4
  12. data/lib/active_support/cache/strategy/local_cache.rb +31 -20
  13. data/lib/active_support/cache.rb +73 -89
  14. data/lib/active_support/callbacks.rb +195 -155
  15. data/lib/active_support/concern.rb +2 -2
  16. data/lib/active_support/concurrency/latch.rb +7 -15
  17. data/lib/active_support/concurrency/share_lock.rb +186 -0
  18. data/lib/active_support/configurable.rb +1 -0
  19. data/lib/active_support/core_ext/array/access.rb +27 -1
  20. data/lib/active_support/core_ext/array/conversions.rb +6 -4
  21. data/lib/active_support/core_ext/array/grouping.rb +9 -18
  22. data/lib/active_support/core_ext/array/inquiry.rb +17 -0
  23. data/lib/active_support/core_ext/array/wrap.rb +5 -4
  24. data/lib/active_support/core_ext/array.rb +1 -0
  25. data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -10
  26. data/lib/active_support/core_ext/class/attribute.rb +10 -9
  27. data/lib/active_support/core_ext/class/subclasses.rb +3 -4
  28. data/lib/active_support/core_ext/class.rb +0 -1
  29. data/lib/active_support/core_ext/date/blank.rb +12 -0
  30. data/lib/active_support/core_ext/date/calculations.rb +1 -1
  31. data/lib/active_support/core_ext/date/conversions.rb +13 -6
  32. data/lib/active_support/core_ext/date.rb +1 -1
  33. data/lib/active_support/core_ext/date_and_time/calculations.rb +109 -25
  34. data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -0
  35. data/lib/active_support/core_ext/date_and_time/zones.rb +3 -4
  36. data/lib/active_support/core_ext/date_time/blank.rb +12 -0
  37. data/lib/active_support/core_ext/date_time/calculations.rb +36 -10
  38. data/lib/active_support/core_ext/date_time/compatibility.rb +5 -0
  39. data/lib/active_support/core_ext/date_time/conversions.rb +2 -0
  40. data/lib/active_support/core_ext/date_time.rb +2 -1
  41. data/lib/active_support/core_ext/enumerable.rb +49 -5
  42. data/lib/active_support/core_ext/file/atomic.rb +30 -25
  43. data/lib/active_support/core_ext/hash/conversions.rb +23 -4
  44. data/lib/active_support/core_ext/hash/deep_merge.rb +1 -1
  45. data/lib/active_support/core_ext/hash/except.rb +9 -8
  46. data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -1
  47. data/lib/active_support/core_ext/hash/keys.rb +23 -19
  48. data/lib/active_support/core_ext/hash/slice.rb +1 -1
  49. data/lib/active_support/core_ext/hash/transform_values.rb +11 -5
  50. data/lib/active_support/core_ext/integer/time.rb +1 -16
  51. data/lib/active_support/core_ext/kernel/concern.rb +2 -0
  52. data/lib/active_support/core_ext/kernel/debugger.rb +3 -10
  53. data/lib/active_support/core_ext/kernel/reporting.rb +2 -83
  54. data/lib/active_support/core_ext/kernel.rb +0 -1
  55. data/lib/active_support/core_ext/load_error.rb +4 -2
  56. data/lib/active_support/core_ext/marshal.rb +12 -11
  57. data/lib/active_support/core_ext/module/aliasing.rb +6 -1
  58. data/lib/active_support/core_ext/module/anonymous.rb +10 -1
  59. data/lib/active_support/core_ext/module/attr_internal.rb +2 -5
  60. data/lib/active_support/core_ext/module/attribute_accessors.rb +15 -15
  61. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +141 -0
  62. data/lib/active_support/core_ext/module/concerning.rb +4 -4
  63. data/lib/active_support/core_ext/module/delegation.rb +35 -25
  64. data/lib/active_support/core_ext/module/deprecation.rb +2 -2
  65. data/lib/active_support/core_ext/module/introspection.rb +4 -0
  66. data/lib/active_support/core_ext/module/method_transplanting.rb +3 -11
  67. data/lib/active_support/core_ext/module/qualified_const.rb +30 -12
  68. data/lib/active_support/core_ext/module/remove_method.rb +23 -0
  69. data/lib/active_support/core_ext/module.rb +1 -0
  70. data/lib/active_support/core_ext/name_error.rb +15 -2
  71. data/lib/active_support/core_ext/numeric/bytes.rb +20 -0
  72. data/lib/active_support/core_ext/numeric/conversions.rb +74 -64
  73. data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
  74. data/lib/active_support/core_ext/numeric/time.rb +24 -19
  75. data/lib/active_support/core_ext/numeric.rb +1 -0
  76. data/lib/active_support/core_ext/object/blank.rb +17 -5
  77. data/lib/active_support/core_ext/object/deep_dup.rb +10 -3
  78. data/lib/active_support/core_ext/object/duplicable.rb +8 -13
  79. data/lib/active_support/core_ext/object/inclusion.rb +2 -2
  80. data/lib/active_support/core_ext/object/instance_variables.rb +1 -1
  81. data/lib/active_support/core_ext/object/json.rb +15 -7
  82. data/lib/active_support/core_ext/object/to_query.rb +1 -1
  83. data/lib/active_support/core_ext/object/try.rb +68 -22
  84. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  85. data/lib/active_support/core_ext/object.rb +0 -1
  86. data/lib/active_support/core_ext/range/conversions.rb +18 -6
  87. data/lib/active_support/core_ext/range/each.rb +16 -18
  88. data/lib/active_support/core_ext/range/include_range.rb +20 -20
  89. data/lib/active_support/core_ext/securerandom.rb +23 -0
  90. data/lib/active_support/core_ext/string/access.rb +1 -1
  91. data/lib/active_support/core_ext/string/behavior.rb +1 -1
  92. data/lib/active_support/core_ext/string/conversions.rb +4 -3
  93. data/lib/active_support/core_ext/string/filters.rb +5 -5
  94. data/lib/active_support/core_ext/string/inflections.rb +32 -5
  95. data/lib/active_support/core_ext/string/multibyte.rb +11 -7
  96. data/lib/active_support/core_ext/string/output_safety.rb +18 -16
  97. data/lib/active_support/core_ext/string/strip.rb +3 -6
  98. data/lib/active_support/core_ext/struct.rb +3 -6
  99. data/lib/active_support/core_ext/time/calculations.rb +36 -11
  100. data/lib/active_support/core_ext/time/compatibility.rb +5 -0
  101. data/lib/active_support/core_ext/time/conversions.rb +4 -2
  102. data/lib/active_support/core_ext/time/marshal.rb +2 -29
  103. data/lib/active_support/core_ext/time/zones.rb +36 -4
  104. data/lib/active_support/core_ext/time.rb +1 -1
  105. data/lib/active_support/core_ext/uri.rb +1 -3
  106. data/lib/active_support/core_ext.rb +2 -1
  107. data/lib/active_support/dependencies/interlock.rb +51 -0
  108. data/lib/active_support/dependencies.rb +87 -95
  109. data/lib/active_support/deprecation/behaviors.rb +16 -2
  110. data/lib/active_support/deprecation/method_wrappers.rb +42 -16
  111. data/lib/active_support/deprecation/proxy_wrappers.rb +47 -24
  112. data/lib/active_support/deprecation/reporting.rb +23 -5
  113. data/lib/active_support/deprecation.rb +1 -1
  114. data/lib/active_support/duration/iso8601_parser.rb +122 -0
  115. data/lib/active_support/duration/iso8601_serializer.rb +51 -0
  116. data/lib/active_support/duration.rb +55 -10
  117. data/lib/active_support/evented_file_update_checker.rb +194 -0
  118. data/lib/active_support/execution_wrapper.rb +117 -0
  119. data/lib/active_support/executor.rb +6 -0
  120. data/lib/active_support/file_update_checker.rb +23 -3
  121. data/lib/active_support/gem_version.rb +3 -3
  122. data/lib/active_support/hash_with_indifferent_access.rb +46 -13
  123. data/lib/active_support/i18n_railtie.rb +25 -4
  124. data/lib/active_support/inflector/inflections.rb +36 -5
  125. data/lib/active_support/inflector/methods.rb +97 -90
  126. data/lib/active_support/inflector/transliterate.rb +36 -21
  127. data/lib/active_support/json/decoding.rb +11 -10
  128. data/lib/active_support/json/encoding.rb +4 -49
  129. data/lib/active_support/key_generator.rb +7 -9
  130. data/lib/active_support/locale/en.yml +2 -0
  131. data/lib/active_support/log_subscriber/test_helper.rb +3 -3
  132. data/lib/active_support/log_subscriber.rb +1 -1
  133. data/lib/active_support/logger.rb +50 -1
  134. data/lib/active_support/logger_silence.rb +8 -4
  135. data/lib/active_support/logger_thread_safe_level.rb +31 -0
  136. data/lib/active_support/message_encryptor.rb +4 -4
  137. data/lib/active_support/message_verifier.rb +70 -8
  138. data/lib/active_support/multibyte/chars.rb +13 -4
  139. data/lib/active_support/multibyte/unicode.rb +44 -21
  140. data/lib/active_support/notifications/fanout.rb +6 -6
  141. data/lib/active_support/notifications/instrumenter.rb +20 -2
  142. data/lib/active_support/notifications.rb +2 -2
  143. data/lib/active_support/number_helper/number_to_currency_converter.rb +7 -9
  144. data/lib/active_support/number_helper/number_to_delimited_converter.rb +8 -3
  145. data/lib/active_support/number_helper/number_to_human_converter.rb +6 -4
  146. data/lib/active_support/number_helper/number_to_human_size_converter.rb +6 -2
  147. data/lib/active_support/number_helper/number_to_percentage_converter.rb +1 -1
  148. data/lib/active_support/number_helper/number_to_phone_converter.rb +11 -2
  149. data/lib/active_support/number_helper/number_to_rounded_converter.rb +30 -25
  150. data/lib/active_support/number_helper.rb +90 -67
  151. data/lib/active_support/ordered_hash.rb +1 -1
  152. data/lib/active_support/ordered_options.rb +15 -1
  153. data/lib/active_support/per_thread_registry.rb +8 -3
  154. data/lib/active_support/rails.rb +2 -2
  155. data/lib/active_support/railtie.rb +6 -1
  156. data/lib/active_support/reloader.rb +129 -0
  157. data/lib/active_support/rescuable.rb +93 -47
  158. data/lib/active_support/security_utils.rb +7 -0
  159. data/lib/active_support/string_inquirer.rb +1 -1
  160. data/lib/active_support/subscriber.rb +5 -10
  161. data/lib/active_support/tagged_logging.rb +3 -1
  162. data/lib/active_support/test_case.rb +15 -29
  163. data/lib/active_support/testing/assertions.rb +15 -13
  164. data/lib/active_support/testing/autorun.rb +8 -1
  165. data/lib/active_support/testing/deprecation.rb +9 -8
  166. data/lib/active_support/testing/file_fixtures.rb +34 -0
  167. data/lib/active_support/testing/isolation.rb +22 -8
  168. data/lib/active_support/testing/method_call_assertions.rb +41 -0
  169. data/lib/active_support/testing/stream.rb +42 -0
  170. data/lib/active_support/testing/time_helpers.rb +13 -10
  171. data/lib/active_support/time_with_zone.rb +135 -46
  172. data/lib/active_support/values/time_zone.rb +95 -47
  173. data/lib/active_support/values/unicode_tables.dat +0 -0
  174. data/lib/active_support/xml_mini/jdom.rb +7 -6
  175. data/lib/active_support/xml_mini/libxml.rb +2 -2
  176. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  177. data/lib/active_support/xml_mini/rexml.rb +7 -8
  178. data/lib/active_support/xml_mini.rb +22 -14
  179. data/lib/active_support.rb +20 -6
  180. metadata +32 -35
  181. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -14
  182. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  183. data/lib/active_support/core_ext/date_time/zones.rb +0 -6
  184. data/lib/active_support/core_ext/object/itself.rb +0 -15
  185. data/lib/active_support/core_ext/thread.rb +0 -86
@@ -1,6 +1,8 @@
1
1
  require 'active_support/duration'
2
2
  require 'active_support/core_ext/time/calculations'
3
3
  require 'active_support/core_ext/time/acts_like'
4
+ require 'active_support/core_ext/date/calculations'
5
+ require 'active_support/core_ext/date/acts_like'
4
6
 
5
7
  class Numeric
6
8
  # Enables the use of time calculations and declarations, like 45.minutes + 2.hours + 4.years.
@@ -16,53 +18,56 @@ class Numeric
16
18
  #
17
19
  # # equivalent to Time.current.advance(months: 4, years: 5)
18
20
  # (4.months + 5.years).from_now
19
- #
20
- # While these methods provide precise calculation when used as in the examples above, care
21
- # should be taken to note that this is not true if the result of `months', `years', etc is
22
- # converted before use:
23
- #
24
- # # equivalent to 30.days.to_i.from_now
25
- # 1.month.to_i.from_now
26
- #
27
- # # equivalent to 365.25.days.to_f.from_now
28
- # 1.year.to_f.from_now
29
- #
30
- # In such cases, Ruby's core
31
- # Date[http://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and
32
- # Time[http://ruby-doc.org/stdlib/libdoc/time/rdoc/Time.html] should be used for precision
33
- # date and time arithmetic.
34
21
  def seconds
35
22
  ActiveSupport::Duration.new(self, [[:seconds, self]])
36
23
  end
37
24
  alias :second :seconds
38
25
 
26
+ # Returns a Duration instance matching the number of minutes provided.
27
+ #
28
+ # 2.minutes # => 2 minutes
39
29
  def minutes
40
- ActiveSupport::Duration.new(self * 60, [[:seconds, self * 60]])
30
+ ActiveSupport::Duration.new(self * 60, [[:minutes, self]])
41
31
  end
42
32
  alias :minute :minutes
43
33
 
34
+ # Returns a Duration instance matching the number of hours provided.
35
+ #
36
+ # 2.hours # => 2 hours
44
37
  def hours
45
- ActiveSupport::Duration.new(self * 3600, [[:seconds, self * 3600]])
38
+ ActiveSupport::Duration.new(self * 3600, [[:hours, self]])
46
39
  end
47
40
  alias :hour :hours
48
41
 
42
+ # Returns a Duration instance matching the number of days provided.
43
+ #
44
+ # 2.days # => 2 days
49
45
  def days
50
46
  ActiveSupport::Duration.new(self * 24.hours, [[:days, self]])
51
47
  end
52
48
  alias :day :days
53
49
 
50
+ # Returns a Duration instance matching the number of weeks provided.
51
+ #
52
+ # 2.weeks # => 2 weeks
54
53
  def weeks
55
- ActiveSupport::Duration.new(self * 7.days, [[:days, self * 7]])
54
+ ActiveSupport::Duration.new(self * 7.days, [[:weeks, self]])
56
55
  end
57
56
  alias :week :weeks
58
57
 
58
+ # Returns a Duration instance matching the number of fortnights provided.
59
+ #
60
+ # 2.fortnights # => 4 weeks
59
61
  def fortnights
60
- ActiveSupport::Duration.new(self * 2.weeks, [[:days, self * 14]])
62
+ ActiveSupport::Duration.new(self * 2.weeks, [[:weeks, self * 2]])
61
63
  end
62
64
  alias :fortnight :fortnights
63
65
 
66
+ # Returns the number of milliseconds equivalent to the seconds provided.
64
67
  # Used with the standard time durations, like 1.hour.in_milliseconds --
65
68
  # so we can feed them to JavaScript functions like getTime().
69
+ #
70
+ # 2.in_milliseconds # => 2_000
66
71
  def in_milliseconds
67
72
  self * 1000
68
73
  end
@@ -1,3 +1,4 @@
1
1
  require 'active_support/core_ext/numeric/bytes'
2
2
  require 'active_support/core_ext/numeric/time'
3
+ require 'active_support/core_ext/numeric/inquiry'
3
4
  require 'active_support/core_ext/numeric/conversions'
@@ -1,12 +1,10 @@
1
- # encoding: utf-8
2
-
3
1
  class Object
4
2
  # An object is blank if it's false, empty, or a whitespace string.
5
- # For example, '', ' ', +nil+, [], and {} are all blank.
3
+ # For example, +false+, '', ' ', +nil+, [], and {} are all blank.
6
4
  #
7
5
  # This simplifies
8
6
  #
9
- # address.nil? || address.empty?
7
+ # !address || address.empty?
10
8
  #
11
9
  # to
12
10
  #
@@ -114,7 +112,10 @@ class String
114
112
  #
115
113
  # @return [true, false]
116
114
  def blank?
117
- BLANK_RE === self
115
+ # The regexp that matches blank strings is expensive. For the case of empty
116
+ # strings we can speed up this method (~3.5x) with an empty? call. The
117
+ # penalty for the rest of strings is marginal.
118
+ empty? || BLANK_RE === self
118
119
  end
119
120
  end
120
121
 
@@ -129,3 +130,14 @@ class Numeric #:nodoc:
129
130
  false
130
131
  end
131
132
  end
133
+
134
+ class Time #:nodoc:
135
+ # No Time is blank:
136
+ #
137
+ # Time.now.blank? # => false
138
+ #
139
+ # @return [false]
140
+ def blank?
141
+ false
142
+ end
143
+ end
@@ -25,7 +25,7 @@ class Array
25
25
  # array[1][2] # => nil
26
26
  # dup[1][2] # => 4
27
27
  def deep_dup
28
- map { |it| it.deep_dup }
28
+ map(&:deep_dup)
29
29
  end
30
30
  end
31
31
 
@@ -39,8 +39,15 @@ class Hash
39
39
  # hash[:a][:c] # => nil
40
40
  # dup[:a][:c] # => "c"
41
41
  def deep_dup
42
- each_with_object(dup) do |(key, value), hash|
43
- hash[key.deep_dup] = value.deep_dup
42
+ hash = dup
43
+ each_pair do |key, value|
44
+ if key.frozen? && ::String === key
45
+ hash[key] = value.deep_dup
46
+ else
47
+ hash.delete(key)
48
+ hash[key.deep_dup] = value.deep_dup
49
+ end
44
50
  end
51
+ hash
45
52
  end
46
53
  end
@@ -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, number and BigDecimal(in 1.9.x) objects;
22
+ # False for +nil+, +false+, +true+, symbol, number, method objects;
23
23
  # true otherwise.
24
24
  def duplicable?
25
25
  true
@@ -70,7 +70,7 @@ class Numeric
70
70
  # Numbers are not duplicable:
71
71
  #
72
72
  # 3.duplicable? # => false
73
- # 3.dup # => TypeError: can't dup Fixnum
73
+ # 3.dup # => TypeError: can't dup Integer
74
74
  def duplicable?
75
75
  false
76
76
  end
@@ -78,17 +78,12 @@ end
78
78
 
79
79
  require 'bigdecimal'
80
80
  class BigDecimal
81
- # Needed to support Ruby 1.9.x, as it doesn't allow dup on BigDecimal, instead
82
- # raises TypeError exception. Checking here on the runtime whether BigDecimal
83
- # will allow dup or not.
84
- begin
85
- BigDecimal.new('4.56').dup
86
-
87
- def duplicable?
88
- true
89
- end
90
- rescue TypeError
91
- # can't dup, so use superclass implementation
81
+ # BigDecimals are duplicable:
82
+ #
83
+ # BigDecimal.new("1.2").duplicable? # => true
84
+ # BigDecimal.new("1.2").dup # => #<BigDecimal:...,'0.12E1',18(18)>
85
+ def duplicable?
86
+ true
92
87
  end
93
88
  end
94
89
 
@@ -5,7 +5,7 @@ class Object
5
5
  # characters = ["Konata", "Kagami", "Tsukasa"]
6
6
  # "Konata".in?(characters) # => true
7
7
  #
8
- # This will throw an ArgumentError if the argument doesn't respond
8
+ # This will throw an +ArgumentError+ if the argument doesn't respond
9
9
  # to +#include?+.
10
10
  def in?(another_object)
11
11
  another_object.include?(self)
@@ -18,7 +18,7 @@ class Object
18
18
  #
19
19
  # params[:bucket_type].presence_in %w( project calendar )
20
20
  #
21
- # This will throw an ArgumentError if the argument doesn't respond to +#include?+.
21
+ # This will throw an +ArgumentError+ if the argument doesn't respond to +#include?+.
22
22
  #
23
23
  # @return [Object]
24
24
  def presence_in(another_object)
@@ -23,6 +23,6 @@ class Object
23
23
  #
24
24
  # C.new(0, 1).instance_variable_names # => ["@y", "@x"]
25
25
  def instance_variable_names
26
- instance_variables.map { |var| var.to_s }
26
+ instance_variables.map(&:to_s)
27
27
  end
28
28
  end
@@ -9,7 +9,6 @@ require 'time'
9
9
  require 'active_support/core_ext/time/conversions'
10
10
  require 'active_support/core_ext/date_time/conversions'
11
11
  require 'active_support/core_ext/date/conversions'
12
- require 'active_support/core_ext/module/aliasing'
13
12
 
14
13
  # The JSON gem adds a few modules to Ruby core classes containing :to_json definition, overwriting
15
14
  # their default behavior. That said, we need to define the basic to_json method in all of them,
@@ -26,22 +25,25 @@ require 'active_support/core_ext/module/aliasing'
26
25
  # bypassed completely. This means that as_json won't be invoked and the JSON gem will simply
27
26
  # ignore any options it does not natively understand. This also means that ::JSON.{generate,dump}
28
27
  # should give exactly the same results with or without active support.
29
- [Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass, Enumerable].each do |klass|
30
- klass.class_eval do
31
- def to_json_with_active_support_encoder(options = nil)
28
+
29
+ module ActiveSupport
30
+ module ToJsonWithActiveSupportEncoder # :nodoc:
31
+ def to_json(options = nil)
32
32
  if options.is_a?(::JSON::State)
33
33
  # Called from JSON.{generate,dump}, forward it to JSON gem's to_json
34
- self.to_json_without_active_support_encoder(options)
34
+ super(options)
35
35
  else
36
36
  # to_json is being invoked directly, use ActiveSupport's encoder
37
37
  ActiveSupport::JSON.encode(self, options)
38
38
  end
39
39
  end
40
-
41
- alias_method_chain :to_json, :active_support_encoder
42
40
  end
43
41
  end
44
42
 
43
+ [Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass, Enumerable].reverse_each do |klass|
44
+ klass.prepend(ActiveSupport::ToJsonWithActiveSupportEncoder)
45
+ end
46
+
45
47
  class Object
46
48
  def as_json(options = nil) #:nodoc:
47
49
  if respond_to?(:to_hash)
@@ -195,3 +197,9 @@ class Process::Status #:nodoc:
195
197
  { :exitstatus => exitstatus, :pid => pid }
196
198
  end
197
199
  end
200
+
201
+ class Exception
202
+ def as_json(options = nil)
203
+ to_s
204
+ end
205
+ end
@@ -38,7 +38,7 @@ class Array
38
38
  # Calls <tt>to_param</tt> on all its elements and joins the result with
39
39
  # slashes. This is used by <tt>url_for</tt> in Action Pack.
40
40
  def to_param
41
- collect { |e| e.to_param }.join '/'
41
+ collect(&:to_param).join '/'
42
42
  end
43
43
 
44
44
  # Converts an array into a string suitable for use as a URL query string,
@@ -1,4 +1,34 @@
1
+ require 'delegate'
2
+
3
+ module ActiveSupport
4
+ module Tryable #:nodoc:
5
+ def try(*a, &b)
6
+ try!(*a, &b) if a.empty? || respond_to?(a.first)
7
+ end
8
+
9
+ def try!(*a, &b)
10
+ if a.empty? && block_given?
11
+ if b.arity == 0
12
+ instance_eval(&b)
13
+ else
14
+ yield self
15
+ end
16
+ else
17
+ public_send(*a, &b)
18
+ end
19
+ end
20
+ end
21
+ end
22
+
1
23
  class Object
24
+ include ActiveSupport::Tryable
25
+
26
+ ##
27
+ # :method: try
28
+ #
29
+ # :call-seq:
30
+ # try(*a, &b)
31
+ #
2
32
  # Invokes the public method whose name goes as first argument just like
3
33
  # +public_send+ does, except that if the receiver does not respond to it the
4
34
  # call returns +nil+ rather than raising an exception.
@@ -21,11 +51,11 @@ class Object
21
51
  #
22
52
  # +try+ will also return +nil+ if the receiver does not respond to the method:
23
53
  #
24
- # @person.try(:non_existing_method) #=> nil
54
+ # @person.try(:non_existing_method) # => nil
25
55
  #
26
56
  # instead of
27
57
  #
28
- # @person.non_existing_method if @person.respond_to?(:non_existing_method) #=> nil
58
+ # @person.non_existing_method if @person.respond_to?(:non_existing_method) # => nil
29
59
  #
30
60
  # +try+ returns +nil+ when called on +nil+ regardless of whether it responds
31
61
  # to the method:
@@ -56,27 +86,40 @@ class Object
56
86
  #
57
87
  # Please also note that +try+ is defined on +Object+. Therefore, it won't work
58
88
  # with instances of classes that do not have +Object+ among their ancestors,
59
- # like direct subclasses of +BasicObject+. For example, using +try+ with
60
- # +SimpleDelegator+ will delegate +try+ to the target instead of calling it on
61
- # the delegator itself.
62
- def try(*a, &b)
63
- try!(*a, &b) if a.empty? || respond_to?(a.first)
64
- end
89
+ # like direct subclasses of +BasicObject+.
65
90
 
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
-
69
- def try!(*a, &b)
70
- if a.empty? && block_given?
71
- if b.arity.zero?
72
- instance_eval(&b)
73
- else
74
- yield self
75
- end
76
- else
77
- public_send(*a, &b)
78
- end
79
- end
91
+ ##
92
+ # :method: try!
93
+ #
94
+ # :call-seq:
95
+ # try!(*a, &b)
96
+ #
97
+ # Same as #try, but raises a +NoMethodError+ exception if the receiver is
98
+ # not +nil+ and does not implement the tried method.
99
+ #
100
+ # "a".try!(:upcase) # => "A"
101
+ # nil.try!(:upcase) # => nil
102
+ # 123.try!(:upcase) # => NoMethodError: undefined method `upcase' for 123:Integer
103
+ end
104
+
105
+ class Delegator
106
+ include ActiveSupport::Tryable
107
+
108
+ ##
109
+ # :method: try
110
+ #
111
+ # :call-seq:
112
+ # try(a*, &b)
113
+ #
114
+ # See Object#try
115
+
116
+ ##
117
+ # :method: try!
118
+ #
119
+ # :call-seq:
120
+ # try!(a*, &b)
121
+ #
122
+ # See Object#try!
80
123
  end
81
124
 
82
125
  class NilClass
@@ -94,6 +137,9 @@ class NilClass
94
137
  nil
95
138
  end
96
139
 
140
+ # Calling +try!+ on +nil+ always returns +nil+.
141
+ #
142
+ # nil.try!(:name) # => nil
97
143
  def try!(*args)
98
144
  nil
99
145
  end
@@ -7,7 +7,7 @@ class Object
7
7
  # provided. Each method called on the block variable must take an options
8
8
  # hash as its final argument.
9
9
  #
10
- # Without <tt>with_options></tt>, this code contains duplication:
10
+ # Without <tt>with_options</tt>, this code contains duplication:
11
11
  #
12
12
  # class Account < ActiveRecord::Base
13
13
  # has_many :customers, dependent: :destroy
@@ -2,7 +2,6 @@ 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'
6
5
  require 'active_support/core_ext/object/try'
7
6
  require 'active_support/core_ext/object/inclusion'
8
7
 
@@ -1,19 +1,31 @@
1
- class Range
1
+ module ActiveSupport::RangeWithFormat
2
2
  RANGE_FORMATS = {
3
3
  :db => Proc.new { |start, stop| "BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'" }
4
4
  }
5
5
 
6
- # Gives a human readable format of the range.
6
+ # Convert range to a formatted string. See RANGE_FORMATS for predefined formats.
7
7
  #
8
- # (1..100).to_formatted_s # => "1..100"
9
- def to_formatted_s(format = :default)
8
+ # range = (1..100) # => 1..100
9
+ #
10
+ # range.to_s # => "1..100"
11
+ # range.to_s(:db) # => "BETWEEN '1' AND '100'"
12
+ #
13
+ # == Adding your own range formats to to_s
14
+ # You can add your own formats to the Range::RANGE_FORMATS hash.
15
+ # Use the format name as the hash key and a Proc instance.
16
+ #
17
+ # # config/initializers/range_formats.rb
18
+ # Range::RANGE_FORMATS[:short] = ->(start, stop) { "Between #{start.to_s(:db)} and #{stop.to_s(:db)}" }
19
+ def to_s(format = :default)
10
20
  if formatter = RANGE_FORMATS[format]
11
21
  formatter.call(first, last)
12
22
  else
13
- to_default_s
23
+ super()
14
24
  end
15
25
  end
16
26
 
17
27
  alias_method :to_default_s, :to_s
18
- alias_method :to_s, :to_formatted_s
28
+ alias_method :to_formatted_s, :to_s
19
29
  end
30
+
31
+ Range.prepend(ActiveSupport::RangeWithFormat)
@@ -1,23 +1,21 @@
1
- require 'active_support/core_ext/module/aliasing'
1
+ module ActiveSupport
2
+ module EachTimeWithZone #:nodoc:
3
+ def each(&block)
4
+ ensure_iteration_allowed
5
+ super
6
+ end
2
7
 
3
- class Range #:nodoc:
8
+ def step(n = 1, &block)
9
+ ensure_iteration_allowed
10
+ super
11
+ end
4
12
 
5
- def each_with_time_with_zone(&block)
6
- ensure_iteration_allowed
7
- each_without_time_with_zone(&block)
8
- end
9
- alias_method_chain :each, :time_with_zone
13
+ private
10
14
 
11
- def step_with_time_with_zone(n = 1, &block)
12
- ensure_iteration_allowed
13
- step_without_time_with_zone(n, &block)
14
- end
15
- alias_method_chain :step, :time_with_zone
16
-
17
- private
18
- def ensure_iteration_allowed
19
- if first.is_a?(Time)
20
- raise TypeError, "can't iterate from #{first.class}"
21
- end
15
+ def ensure_iteration_allowed
16
+ raise TypeError, "can't iterate from #{first.class}" if first.is_a?(Time)
17
+ end
22
18
  end
23
19
  end
20
+
21
+ Range.prepend(ActiveSupport::EachTimeWithZone)
@@ -1,23 +1,23 @@
1
- require 'active_support/core_ext/module/aliasing'
2
-
3
- class Range
4
- # Extends the default Range#include? to support range comparisons.
5
- # (1..5).include?(1..5) # => true
6
- # (1..5).include?(2..3) # => true
7
- # (1..5).include?(2..6) # => false
8
- #
9
- # The native Range#include? behavior is untouched.
10
- # ('a'..'f').include?('c') # => true
11
- # (5..9).include?(11) # => false
12
- def include_with_range?(value)
13
- if value.is_a?(::Range)
14
- # 1...10 includes 1..9 but it does not include 1..10.
15
- operator = exclude_end? && !value.exclude_end? ? :< : :<=
16
- include_without_range?(value.first) && value.last.send(operator, last)
17
- else
18
- include_without_range?(value)
1
+ module ActiveSupport
2
+ module IncludeWithRange #:nodoc:
3
+ # Extends the default Range#include? to support range comparisons.
4
+ # (1..5).include?(1..5) # => true
5
+ # (1..5).include?(2..3) # => true
6
+ # (1..5).include?(2..6) # => false
7
+ #
8
+ # The native Range#include? behavior is untouched.
9
+ # ('a'..'f').include?('c') # => true
10
+ # (5..9).include?(11) # => false
11
+ def include?(value)
12
+ if value.is_a?(::Range)
13
+ # 1...10 includes 1..9 but it does not include 1..10.
14
+ operator = exclude_end? && !value.exclude_end? ? :< : :<=
15
+ super(value.first) && value.last.send(operator, last)
16
+ else
17
+ super
18
+ end
19
19
  end
20
20
  end
21
-
22
- alias_method_chain :include?, :range
23
21
  end
22
+
23
+ Range.prepend(ActiveSupport::IncludeWithRange)
@@ -0,0 +1,23 @@
1
+ require 'securerandom'
2
+
3
+ module SecureRandom
4
+ BASE58_ALPHABET = ('0'..'9').to_a + ('A'..'Z').to_a + ('a'..'z').to_a - ['0', 'O', 'I', 'l']
5
+ # SecureRandom.base58 generates a random base58 string.
6
+ #
7
+ # The argument _n_ specifies the length, of the random string to be generated.
8
+ #
9
+ # If _n_ is not specified or is nil, 16 is assumed. It may be larger in the future.
10
+ #
11
+ # The result may contain alphanumeric characters except 0, O, I and l
12
+ #
13
+ # p SecureRandom.base58 # => "4kUgL2pdQMSCQtjE"
14
+ # p SecureRandom.base58(24) # => "77TMHrHJFvFDwodq8w7Ev2m7"
15
+ #
16
+ def self.base58(n = 16)
17
+ SecureRandom.random_bytes(n).unpack("C*").map do |byte|
18
+ idx = byte % 64
19
+ idx = SecureRandom.random_number(58) if idx >= 58
20
+ BASE58_ALPHABET[idx]
21
+ end.join
22
+ end
23
+ end
@@ -1,5 +1,5 @@
1
1
  class String
2
- # If you pass a single Fixnum, returns a substring of one character at that
2
+ # If you pass a single integer, returns a substring of one character at that
3
3
  # position. The first character of the string is at position 0, the next at
4
4
  # position 1, and so on. If a range is supplied, a substring containing
5
5
  # characters at offsets given by the range is returned. In both cases, if an
@@ -1,5 +1,5 @@
1
1
  class String
2
- # Enable more predictable duck-typing on String-like classes. See <tt>Object#acts_like?</tt>.
2
+ # Enables more predictable duck-typing on String-like classes. See <tt>Object#acts_like?</tt>.
3
3
  def acts_like_string?
4
4
  true
5
5
  end
@@ -14,11 +14,12 @@ class String
14
14
  # "06:12".to_time # => 2012-12-13 06:12:00 +0100
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
- # "2012-12-13T06:12".to_time(:utc) # => 2012-12-13 05:12:00 UTC
17
+ # "2012-12-13T06:12".to_time(:utc) # => 2012-12-13 06:12:00 UTC
18
18
  # "12/13/2012".to_time # => ArgumentError: argument out of range
19
19
  def to_time(form = :local)
20
20
  parts = Date._parse(self, false)
21
- return if parts.empty?
21
+ used_keys = %i(year mon mday hour min sec sec_fraction offset)
22
+ return if (parts.keys & used_keys).empty?
22
23
 
23
24
  now = Time.now
24
25
  time = Time.new(
@@ -31,7 +32,7 @@ class String
31
32
  parts.fetch(:offset, form == :utc ? 0 : nil)
32
33
  )
33
34
 
34
- form == :utc ? time.utc : time.getlocal
35
+ form == :utc ? time.utc : time.to_time
35
36
  end
36
37
 
37
38
  # Converts a string to a Date value.
@@ -17,15 +17,15 @@ class String
17
17
  # str.squish! # => "foo bar boo"
18
18
  # str # => "foo bar boo"
19
19
  def squish!
20
- gsub!(/\A[[:space:]]+/, '')
21
- gsub!(/[[:space:]]+\z/, '')
22
20
  gsub!(/[[:space:]]+/, ' ')
21
+ strip!
23
22
  self
24
23
  end
25
24
 
26
25
  # Returns a new string with all occurrences of the patterns removed.
27
26
  # str = "foo bar test"
28
27
  # str.remove(" test") # => "foo bar"
28
+ # str.remove(" test", /bar/) # => "foo "
29
29
  # str # => "foo bar test"
30
30
  def remove(*patterns)
31
31
  dup.remove!(*patterns)
@@ -33,8 +33,8 @@ class String
33
33
 
34
34
  # Alters the string by removing all occurrences of the patterns.
35
35
  # str = "foo bar test"
36
- # str.remove!(" test") # => "foo bar"
37
- # str # => "foo bar"
36
+ # str.remove!(" test", /bar/) # => "foo "
37
+ # str # => "foo "
38
38
  def remove!(*patterns)
39
39
  patterns.each do |pattern|
40
40
  gsub! pattern, ""
@@ -93,7 +93,7 @@ class String
93
93
  def truncate_words(words_count, options = {})
94
94
  sep = options[:separator] || /\s+/
95
95
  sep = Regexp.escape(sep.to_s) unless Regexp === sep
96
- if self =~ /\A((?:.+?#{sep}){#{words_count - 1}}.+?)#{sep}.*/m
96
+ if self =~ /\A((?>.+?#{sep}){#{words_count - 1}}.+?)#{sep}.*/m
97
97
  $1 + (options[:omission] || '...')
98
98
  else
99
99
  dup