activesupport 3.2.22.5 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +364 -135
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -4
  5. data/lib/active_support/backtrace_cleaner.rb +33 -25
  6. data/lib/active_support/basic_object.rb +7 -17
  7. data/lib/active_support/benchmarkable.rb +19 -15
  8. data/lib/active_support/buffered_logger.rb +9 -113
  9. data/lib/active_support/cache/file_store.rb +14 -14
  10. data/lib/active_support/cache/mem_cache_store.rb +24 -30
  11. data/lib/active_support/cache/memory_store.rb +2 -0
  12. data/lib/active_support/cache/strategy/local_cache.rb +48 -37
  13. data/lib/active_support/cache.rb +228 -183
  14. data/lib/active_support/callbacks.rb +201 -253
  15. data/lib/active_support/concern.rb +16 -23
  16. data/lib/active_support/concurrency/latch.rb +27 -0
  17. data/lib/active_support/configurable.rb +69 -12
  18. data/lib/active_support/core_ext/array/access.rb +17 -9
  19. data/lib/active_support/core_ext/array/conversions.rb +115 -55
  20. data/lib/active_support/core_ext/array/extract_options.rb +2 -2
  21. data/lib/active_support/core_ext/array/grouping.rb +21 -22
  22. data/lib/active_support/core_ext/array/uniq_by.rb +12 -9
  23. data/lib/active_support/core_ext/array/wrap.rb +13 -16
  24. data/lib/active_support/core_ext/array.rb +0 -1
  25. data/lib/active_support/core_ext/benchmark.rb +7 -0
  26. data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -24
  27. data/lib/active_support/core_ext/class/attribute.rb +40 -32
  28. data/lib/active_support/core_ext/class/attribute_accessors.rb +14 -12
  29. data/lib/active_support/core_ext/class/delegating_attributes.rb +15 -19
  30. data/lib/active_support/core_ext/class/subclasses.rb +11 -5
  31. data/lib/active_support/core_ext/date/calculations.rb +44 -187
  32. data/lib/active_support/core_ext/date/conversions.rb +16 -38
  33. data/lib/active_support/core_ext/date/zones.rb +25 -2
  34. data/lib/active_support/core_ext/date.rb +5 -0
  35. data/lib/active_support/core_ext/date_and_time/calculations.rb +232 -0
  36. data/lib/active_support/core_ext/date_time/acts_like.rb +0 -1
  37. data/lib/active_support/core_ext/date_time/calculations.rb +77 -62
  38. data/lib/active_support/core_ext/date_time/conversions.rb +21 -33
  39. data/lib/active_support/core_ext/date_time/zones.rb +11 -8
  40. data/lib/active_support/core_ext/date_time.rb +4 -0
  41. data/lib/active_support/core_ext/enumerable.rb +26 -73
  42. data/lib/active_support/core_ext/file/atomic.rb +27 -11
  43. data/lib/active_support/core_ext/file.rb +0 -1
  44. data/lib/active_support/core_ext/hash/conversions.rb +145 -79
  45. data/lib/active_support/core_ext/hash/deep_merge.rb +14 -8
  46. data/lib/active_support/core_ext/hash/diff.rb +5 -4
  47. data/lib/active_support/core_ext/hash/except.rb +1 -9
  48. data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -5
  49. data/lib/active_support/core_ext/hash/keys.rb +108 -24
  50. data/lib/active_support/core_ext/hash/reverse_merge.rb +2 -3
  51. data/lib/active_support/core_ext/hash/slice.rb +12 -12
  52. data/lib/active_support/core_ext/hash.rb +0 -1
  53. data/lib/active_support/core_ext/integer/inflections.rb +13 -1
  54. data/lib/active_support/core_ext/integer/time.rb +17 -12
  55. data/lib/active_support/core_ext/kernel/debugger.rb +2 -2
  56. data/lib/active_support/core_ext/kernel/reporting.rb +36 -22
  57. data/lib/active_support/core_ext/kernel/singleton_class.rb +0 -7
  58. data/lib/active_support/core_ext/load_error.rb +7 -5
  59. data/lib/active_support/core_ext/logger.rb +7 -23
  60. data/lib/active_support/core_ext/marshal.rb +21 -0
  61. data/lib/active_support/core_ext/module/aliasing.rb +8 -9
  62. data/lib/active_support/core_ext/module/anonymous.rb +2 -7
  63. data/lib/active_support/core_ext/module/attr_internal.rb +0 -1
  64. data/lib/active_support/core_ext/module/attribute_accessors.rb +12 -10
  65. data/lib/active_support/core_ext/module/delegation.rb +92 -49
  66. data/lib/active_support/core_ext/module/deprecation.rb +19 -3
  67. data/lib/active_support/core_ext/module/introspection.rb +17 -27
  68. data/lib/active_support/core_ext/module/qualified_const.rb +8 -20
  69. data/lib/active_support/core_ext/module/remove_method.rb +1 -5
  70. data/lib/active_support/core_ext/module.rb +1 -3
  71. data/lib/active_support/core_ext/numeric/conversions.rb +135 -0
  72. data/lib/active_support/core_ext/numeric/time.rb +6 -6
  73. data/lib/active_support/core_ext/numeric.rb +1 -0
  74. data/lib/active_support/core_ext/object/acts_like.rb +4 -4
  75. data/lib/active_support/core_ext/object/blank.rb +7 -23
  76. data/lib/active_support/core_ext/object/deep_dup.rb +46 -0
  77. data/lib/active_support/core_ext/object/duplicable.rb +1 -30
  78. data/lib/active_support/core_ext/object/inclusion.rb +8 -7
  79. data/lib/active_support/core_ext/object/instance_variables.rb +7 -12
  80. data/lib/active_support/core_ext/object/to_json.rb +8 -0
  81. data/lib/active_support/core_ext/object/to_param.rb +5 -2
  82. data/lib/active_support/core_ext/object/try.rb +46 -25
  83. data/lib/active_support/core_ext/object/with_options.rb +7 -8
  84. data/lib/active_support/core_ext/object.rb +1 -0
  85. data/lib/active_support/core_ext/proc.rb +3 -0
  86. data/lib/active_support/core_ext/range/conversions.rb +0 -2
  87. data/lib/active_support/core_ext/range/include_range.rb +3 -1
  88. data/lib/active_support/core_ext/range/overlaps.rb +1 -1
  89. data/lib/active_support/core_ext/range.rb +0 -2
  90. data/lib/active_support/core_ext/string/access.rb +95 -90
  91. data/lib/active_support/core_ext/string/conversions.rb +27 -38
  92. data/lib/active_support/core_ext/string/encoding.rb +6 -9
  93. data/lib/active_support/core_ext/string/filters.rb +24 -18
  94. data/lib/active_support/core_ext/string/indent.rb +43 -0
  95. data/lib/active_support/core_ext/string/inflections.rb +70 -60
  96. data/lib/active_support/core_ext/string/inquiry.rb +2 -2
  97. data/lib/active_support/core_ext/string/multibyte.rb +41 -64
  98. data/lib/active_support/core_ext/string/output_safety.rb +59 -51
  99. data/lib/active_support/core_ext/string/zones.rb +13 -0
  100. data/lib/active_support/core_ext/string.rb +2 -3
  101. data/lib/active_support/core_ext/struct.rb +6 -0
  102. data/lib/active_support/core_ext/thread.rb +74 -0
  103. data/lib/active_support/core_ext/time/calculations.rb +108 -184
  104. data/lib/active_support/core_ext/time/conversions.rb +27 -51
  105. data/lib/active_support/core_ext/time/marshal.rb +0 -27
  106. data/lib/active_support/core_ext/time/zones.rb +27 -17
  107. data/lib/active_support/core_ext/time.rb +5 -0
  108. data/lib/active_support/core_ext/uri.rb +13 -17
  109. data/lib/active_support/core_ext.rb +3 -2
  110. data/lib/active_support/dependencies/autoload.rb +47 -20
  111. data/lib/active_support/dependencies.rb +160 -141
  112. data/lib/active_support/deprecation/behaviors.rb +44 -30
  113. data/lib/active_support/deprecation/instance_delegator.rb +24 -0
  114. data/lib/active_support/deprecation/method_wrappers.rb +33 -18
  115. data/lib/active_support/deprecation/proxy_wrappers.rb +58 -13
  116. data/lib/active_support/deprecation/reporting.rb +40 -11
  117. data/lib/active_support/deprecation.rb +39 -14
  118. data/lib/active_support/descendants_tracker.rb +34 -19
  119. data/lib/active_support/duration.rb +6 -8
  120. data/lib/active_support/file_update_checker.rb +63 -47
  121. data/lib/active_support/gzip.rb +11 -5
  122. data/lib/active_support/hash_with_indifferent_access.rb +127 -42
  123. data/lib/active_support/i18n.rb +4 -0
  124. data/lib/active_support/i18n_railtie.rb +5 -22
  125. data/lib/active_support/inflections.rb +14 -12
  126. data/lib/active_support/inflector/inflections.rb +108 -71
  127. data/lib/active_support/inflector/methods.rb +181 -160
  128. data/lib/active_support/inflector/transliterate.rb +16 -17
  129. data/lib/active_support/json/decoding.rb +18 -17
  130. data/lib/active_support/json/encoding.rb +93 -39
  131. data/lib/active_support/json/variable.rb +10 -1
  132. data/lib/active_support/key_generator.rb +75 -0
  133. data/lib/active_support/lazy_load_hooks.rb +21 -19
  134. data/lib/active_support/locale/en.yml +100 -3
  135. data/lib/active_support/log_subscriber/test_helper.rb +18 -15
  136. data/lib/active_support/log_subscriber.rb +35 -52
  137. data/lib/active_support/logger.rb +57 -0
  138. data/lib/active_support/logger_silence.rb +24 -0
  139. data/lib/active_support/message_encryptor.rb +38 -35
  140. data/lib/active_support/message_verifier.rb +9 -15
  141. data/lib/active_support/multibyte/chars.rb +80 -333
  142. data/lib/active_support/multibyte/unicode.rb +74 -64
  143. data/lib/active_support/multibyte.rb +5 -28
  144. data/lib/active_support/notifications/fanout.rb +112 -18
  145. data/lib/active_support/notifications/instrumenter.rb +33 -14
  146. data/lib/active_support/notifications.rb +79 -26
  147. data/lib/active_support/number_helper.rb +637 -0
  148. data/lib/active_support/ordered_hash.rb +8 -190
  149. data/lib/active_support/ordered_options.rb +21 -23
  150. data/lib/active_support/per_thread_registry.rb +52 -0
  151. data/lib/active_support/proxy_object.rb +13 -0
  152. data/lib/active_support/rails.rb +27 -0
  153. data/lib/active_support/railtie.rb +12 -32
  154. data/lib/active_support/rescuable.rb +9 -4
  155. data/lib/active_support/string_inquirer.rb +13 -8
  156. data/lib/active_support/subscriber.rb +93 -0
  157. data/lib/active_support/tagged_logging.rb +51 -73
  158. data/lib/active_support/test_case.rb +46 -17
  159. data/lib/active_support/testing/assertions.rb +56 -26
  160. data/lib/active_support/testing/autorun.rb +5 -0
  161. data/lib/active_support/testing/constant_lookup.rb +54 -0
  162. data/lib/active_support/testing/declarative.rb +1 -1
  163. data/lib/active_support/testing/deprecation.rb +0 -19
  164. data/lib/active_support/testing/isolation.rb +29 -58
  165. data/lib/active_support/testing/pending.rb +5 -43
  166. data/lib/active_support/testing/setup_and_teardown.rb +6 -92
  167. data/lib/active_support/testing/tagged_logging.rb +25 -0
  168. data/lib/active_support/time.rb +6 -21
  169. data/lib/active_support/time_with_zone.rb +80 -43
  170. data/lib/active_support/values/time_zone.rb +81 -60
  171. data/lib/active_support/values/unicode_tables.dat +0 -0
  172. data/lib/active_support/version.rb +7 -6
  173. data/lib/active_support/xml_mini/jdom.rb +9 -11
  174. data/lib/active_support/xml_mini/libxml.rb +1 -2
  175. data/lib/active_support/xml_mini/libxmlsax.rb +2 -3
  176. data/lib/active_support/xml_mini/nokogiri.rb +1 -2
  177. data/lib/active_support/xml_mini/nokogirisax.rb +2 -3
  178. data/lib/active_support/xml_mini/rexml.rb +6 -8
  179. data/lib/active_support/xml_mini.rb +35 -17
  180. data/lib/active_support.rb +8 -21
  181. metadata +104 -72
  182. data/lib/active_support/base64.rb +0 -54
  183. data/lib/active_support/core_ext/array/random_access.rb +0 -30
  184. data/lib/active_support/core_ext/date/freeze.rb +0 -33
  185. data/lib/active_support/core_ext/exception.rb +0 -3
  186. data/lib/active_support/core_ext/file/path.rb +0 -5
  187. data/lib/active_support/core_ext/float/rounding.rb +0 -19
  188. data/lib/active_support/core_ext/float.rb +0 -1
  189. data/lib/active_support/core_ext/hash/deep_dup.rb +0 -18
  190. data/lib/active_support/core_ext/io.rb +0 -15
  191. data/lib/active_support/core_ext/module/method_names.rb +0 -14
  192. data/lib/active_support/core_ext/module/synchronization.rb +0 -45
  193. data/lib/active_support/core_ext/process/daemon.rb +0 -23
  194. data/lib/active_support/core_ext/process.rb +0 -1
  195. data/lib/active_support/core_ext/range/blockless_step.rb +0 -29
  196. data/lib/active_support/core_ext/range/cover.rb +0 -3
  197. data/lib/active_support/core_ext/rexml.rb +0 -46
  198. data/lib/active_support/core_ext/string/interpolation.rb +0 -2
  199. data/lib/active_support/core_ext/string/xchar.rb +0 -18
  200. data/lib/active_support/core_ext/time/publicize_conversion_methods.rb +0 -10
  201. data/lib/active_support/memoizable.rb +0 -116
  202. data/lib/active_support/multibyte/exceptions.rb +0 -8
  203. data/lib/active_support/multibyte/utils.rb +0 -60
  204. data/lib/active_support/ruby/shim.rb +0 -22
  205. data/lib/active_support/security_utils.rb +0 -27
  206. data/lib/active_support/testing/mochaing.rb +0 -7
  207. data/lib/active_support/testing/performance/jruby.rb +0 -115
  208. data/lib/active_support/testing/performance/rubinius.rb +0 -113
  209. data/lib/active_support/testing/performance/ruby/mri.rb +0 -57
  210. data/lib/active_support/testing/performance/ruby/yarv.rb +0 -57
  211. data/lib/active_support/testing/performance/ruby.rb +0 -152
  212. data/lib/active_support/testing/performance.rb +0 -317
  213. data/lib/active_support/time/autoload.rb +0 -5
  214. data/lib/active_support/whiny_nil.rb +0 -24
@@ -1,39 +1,58 @@
1
1
  class Object
2
- # Invokes the method identified by the symbol +method+, passing it any arguments
3
- # and/or the block specified, just like the regular Ruby <tt>Object#send</tt> does.
2
+ # Invokes the public method whose name goes as first argument just like
3
+ # +public_send+ does, except that if the receiver does not respond to it the
4
+ # call returns +nil+ rather than raising an exception.
4
5
  #
5
- # *Unlike* that method however, a +NoMethodError+ exception will *not* be raised
6
- # and +nil+ will be returned instead, if the receiving object is a +nil+ object or NilClass.
6
+ # This method is defined to be able to write
7
7
  #
8
- # If try is called without a method to call, it will yield any given block with the object.
9
- #
10
- # Please also note that +try+ is defined on +Object+, therefore it won't work with
11
- # subclasses of +BasicObject+. For example, using try with +SimpleDelegator+ will
12
- # delegate +try+ to target instead of calling it on delegator itself.
8
+ # @person.try(:name)
13
9
  #
14
- # ==== Examples
10
+ # instead of
15
11
  #
16
- # Without +try+
17
- # @person && @person.name
18
- # or
19
12
  # @person ? @person.name : nil
20
13
  #
21
- # With +try+
22
- # @person.try(:name)
14
+ # +try+ returns +nil+ when called on +nil+ regardless of whether it responds
15
+ # to the method:
16
+ #
17
+ # nil.try(:to_i) # => nil, rather than 0
18
+ #
19
+ # Arguments and blocks are forwarded to the method if invoked:
20
+ #
21
+ # @posts.try(:each_slice, 2) do |a, b|
22
+ # ...
23
+ # end
24
+ #
25
+ # The number of arguments in the signature must match. If the object responds
26
+ # to the method the call is attempted and +ArgumentError+ is still raised
27
+ # otherwise.
28
+ #
29
+ # If +try+ is called without arguments it yields the receiver to a given
30
+ # block unless it is +nil+:
23
31
  #
24
- # +try+ also accepts arguments and/or a block, for the method it is trying
25
- # Person.try(:find, 1)
26
- # @people.try(:collect) {|p| p.name}
32
+ # @person.try do |p|
33
+ # ...
34
+ # end
27
35
  #
28
- # Without a method argument try will yield to the block unless the receiver is nil.
29
- # @person.try { |p| "#{p.first_name} #{p.last_name}" }
30
- #--
31
- # +try+ behaves like +Object#send+, unless called on +NilClass+.
36
+ # Please also note that +try+ is defined on +Object+, therefore it won't work
37
+ # with instances of classes that do not have +Object+ among their ancestors,
38
+ # like direct subclasses of +BasicObject+. For example, using +try+ with
39
+ # +SimpleDelegator+ will delegate +try+ to the target instead of calling it on
40
+ # delegator itself.
32
41
  def try(*a, &b)
33
42
  if a.empty? && block_given?
34
43
  yield self
35
44
  else
36
- __send__(*a, &b)
45
+ public_send(*a, &b) if respond_to?(a.first)
46
+ end
47
+ end
48
+
49
+ # Same as #try, but will raise a NoMethodError exception if the receiving is not nil and
50
+ # does not implemented the tried method.
51
+ def try!(*a, &b)
52
+ if a.empty? && block_given?
53
+ yield self
54
+ else
55
+ public_send(*a, &b)
37
56
  end
38
57
  end
39
58
  end
@@ -42,8 +61,6 @@ class NilClass
42
61
  # Calling +try+ on +nil+ always returns +nil+.
43
62
  # It becomes specially helpful when navigating through associations that may return +nil+.
44
63
  #
45
- # === Examples
46
- #
47
64
  # nil.try(:name) # => nil
48
65
  #
49
66
  # Without +try+
@@ -54,4 +71,8 @@ class NilClass
54
71
  def try(*args)
55
72
  nil
56
73
  end
74
+
75
+ def try!(*args)
76
+ nil
77
+ end
57
78
  end
@@ -10,16 +10,16 @@ class Object
10
10
  # Without <tt>with_options></tt>, this code contains duplication:
11
11
  #
12
12
  # class Account < ActiveRecord::Base
13
- # has_many :customers, :dependent => :destroy
14
- # has_many :products, :dependent => :destroy
15
- # has_many :invoices, :dependent => :destroy
16
- # has_many :expenses, :dependent => :destroy
13
+ # has_many :customers, dependent: :destroy
14
+ # has_many :products, dependent: :destroy
15
+ # has_many :invoices, dependent: :destroy
16
+ # has_many :expenses, dependent: :destroy
17
17
  # end
18
18
  #
19
19
  # Using <tt>with_options</tt>, we can remove the duplication:
20
20
  #
21
21
  # class Account < ActiveRecord::Base
22
- # with_options :dependent => :destroy do |assoc|
22
+ # with_options dependent: :destroy do |assoc|
23
23
  # assoc.has_many :customers
24
24
  # assoc.has_many :products
25
25
  # assoc.has_many :invoices
@@ -29,14 +29,13 @@ class Object
29
29
  #
30
30
  # It can also be used with an explicit receiver:
31
31
  #
32
- # I18n.with_options :locale => user.locale, :scope => "newsletter" do |i18n|
32
+ # I18n.with_options locale: user.locale, scope: 'newsletter' do |i18n|
33
33
  # subject i18n.t :subject
34
- # body i18n.t :body, :user_name => user.name
34
+ # body i18n.t :body, user_name: user.name
35
35
  # end
36
36
  #
37
37
  # <tt>with_options</tt> can also be nested since the call is forwarded to its receiver.
38
38
  # Each nesting level will merge inherited defaults in addition to their own.
39
- #
40
39
  def with_options(options)
41
40
  yield ActiveSupport::OptionMerger.new(self, options)
42
41
  end
@@ -1,6 +1,7 @@
1
1
  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
+ require 'active_support/core_ext/object/deep_dup'
4
5
  require 'active_support/core_ext/object/try'
5
6
  require 'active_support/core_ext/object/inclusion'
6
7
 
@@ -1,7 +1,10 @@
1
1
  require "active_support/core_ext/kernel/singleton_class"
2
+ require "active_support/deprecation"
2
3
 
3
4
  class Proc #:nodoc:
4
5
  def bind(object)
6
+ ActiveSupport::Deprecation.warn 'Proc#bind is deprecated and will be removed in future versions'
7
+
5
8
  block, time = self, Time.now
6
9
  object.class_eval do
7
10
  method_name = "__bind_#{time.to_i}_#{time.usec}"
@@ -5,8 +5,6 @@ class Range
5
5
 
6
6
  # Gives a human readable format of the range.
7
7
  #
8
- # ==== Example
9
- #
10
8
  # (1..100).to_formatted_s # => "1..100"
11
9
  def to_formatted_s(format = :default)
12
10
  if formatter = RANGE_FORMATS[format]
@@ -1,3 +1,5 @@
1
+ require 'active_support/core_ext/module/aliasing'
2
+
1
3
  class Range
2
4
  # Extends the default Range#include? to support range comparisons.
3
5
  # (1..5).include?(1..5) # => true
@@ -5,7 +7,7 @@ class Range
5
7
  # (1..5).include?(2..6) # => false
6
8
  #
7
9
  # The native Range#include? behavior is untouched.
8
- # ("a".."f").include?("c") # => true
10
+ # ('a'..'f').include?('c') # => true
9
11
  # (5..9).include?(11) # => false
10
12
  def include_with_range?(value)
11
13
  if value.is_a?(::Range)
@@ -3,6 +3,6 @@ class Range
3
3
  # (1..5).overlaps?(4..6) # => true
4
4
  # (1..5).overlaps?(7..9) # => false
5
5
  def overlaps?(other)
6
- include?(other.first) || other.include?(first)
6
+ cover?(other.first) || other.cover?(first)
7
7
  end
8
8
  end
@@ -1,5 +1,3 @@
1
- require 'active_support/core_ext/range/blockless_step'
2
1
  require 'active_support/core_ext/range/conversions'
3
2
  require 'active_support/core_ext/range/include_range'
4
3
  require 'active_support/core_ext/range/overlaps'
5
- require 'active_support/core_ext/range/cover'
@@ -1,99 +1,104 @@
1
- require "active_support/multibyte"
2
-
3
1
  class String
4
- unless '1.9'.respond_to?(:force_encoding)
5
- # Returns the character at the +position+ treating the string as an array (where 0 is the first character).
6
- #
7
- # Examples:
8
- # "hello".at(0) # => "h"
9
- # "hello".at(4) # => "o"
10
- # "hello".at(10) # => ERROR if < 1.9, nil in 1.9
11
- def at(position)
12
- mb_chars[position, 1].to_s
13
- end
14
-
15
- # Returns the remaining of the string from the +position+ treating the string as an array (where 0 is the first character).
16
- #
17
- # Examples:
18
- # "hello".from(0) # => "hello"
19
- # "hello".from(2) # => "llo"
20
- # "hello".from(10) # => "" if < 1.9, nil in 1.9
21
- def from(position)
22
- mb_chars[position..-1].to_s
23
- end
24
-
25
- # Returns the beginning of the string up to the +position+ treating the string as an array (where 0 is the first character).
26
- #
27
- # Examples:
28
- # "hello".to(0) # => "h"
29
- # "hello".to(2) # => "hel"
30
- # "hello".to(10) # => "hello"
31
- def to(position)
32
- mb_chars[0..position].to_s
33
- end
34
-
35
- # Returns the first character of the string or the first +limit+ characters.
36
- #
37
- # Examples:
38
- # "hello".first # => "h"
39
- # "hello".first(2) # => "he"
40
- # "hello".first(10) # => "hello"
41
- def first(limit = 1)
42
- if limit == 0
43
- ''
44
- elsif limit >= size
45
- self
46
- else
47
- mb_chars[0...limit].to_s
48
- end
49
- end
50
-
51
- # Returns the last character of the string or the last +limit+ characters.
52
- #
53
- # Examples:
54
- # "hello".last # => "o"
55
- # "hello".last(2) # => "lo"
56
- # "hello".last(10) # => "hello"
57
- def last(limit = 1)
58
- if limit == 0
59
- ''
60
- elsif limit >= size
61
- self
62
- else
63
- mb_chars[(-limit)..-1].to_s
64
- end
65
- end
66
- else
67
- def at(position)
68
- self[position]
69
- end
2
+ # If you pass a single Fixnum, returns a substring of one character at that
3
+ # position. The first character of the string is at position 0, the next at
4
+ # position 1, and so on. If a range is supplied, a substring containing
5
+ # characters at offsets given by the range is returned. In both cases, if an
6
+ # offset is negative, it is counted from the end of the string. Returns nil
7
+ # if the initial offset falls outside the string. Returns an empty string if
8
+ # the beginning of the range is greater than the end of the string.
9
+ #
10
+ # str = "hello"
11
+ # str.at(0) #=> "h"
12
+ # str.at(1..3) #=> "ell"
13
+ # str.at(-2) #=> "l"
14
+ # str.at(-2..-1) #=> "lo"
15
+ # str.at(5) #=> nil
16
+ # str.at(5..-1) #=> ""
17
+ #
18
+ # If a Regexp is given, the matching portion of the string is returned.
19
+ # If a String is given, that given string is returned if it occurs in
20
+ # the string. In both cases, nil is returned if there is no match.
21
+ #
22
+ # str = "hello"
23
+ # str.at(/lo/) #=> "lo"
24
+ # str.at(/ol/) #=> nil
25
+ # str.at("lo") #=> "lo"
26
+ # str.at("ol") #=> nil
27
+ def at(position)
28
+ self[position]
29
+ end
70
30
 
71
- def from(position)
72
- self[position..-1]
73
- end
31
+ # Returns a substring from the given position to the end of the string.
32
+ # If the position is negative, it is counted from the end of the string.
33
+ #
34
+ # str = "hello"
35
+ # str.from(0) #=> "hello"
36
+ # str.from(3) #=> "lo"
37
+ # str.from(-2) #=> "lo"
38
+ #
39
+ # You can mix it with +to+ method and do fun things like:
40
+ #
41
+ # str = "hello"
42
+ # str.from(0).to(-1) #=> "hello"
43
+ # str.from(1).to(-2) #=> "ell"
44
+ def from(position)
45
+ self[position..-1]
46
+ end
74
47
 
75
- def to(position)
76
- self[0..position]
77
- end
48
+ # Returns a substring from the beginning of the string to the given position.
49
+ # If the position is negative, it is counted from the end of the string.
50
+ #
51
+ # str = "hello"
52
+ # str.to(0) #=> "h"
53
+ # str.to(3) #=> "hell"
54
+ # str.to(-2) #=> "hell"
55
+ #
56
+ # You can mix it with +from+ method and do fun things like:
57
+ #
58
+ # str = "hello"
59
+ # str.from(0).to(-1) #=> "hello"
60
+ # str.from(1).to(-2) #=> "ell"
61
+ def to(position)
62
+ self[0..position]
63
+ end
78
64
 
79
- def first(limit = 1)
80
- if limit == 0
81
- ''
82
- elsif limit >= size
83
- self
84
- else
85
- to(limit - 1)
86
- end
65
+ # Returns the first character. If a limit is supplied, returns a substring
66
+ # from the beginning of the string until it reaches the limit value. If the
67
+ # given limit is greater than or equal to the string length, returns self.
68
+ #
69
+ # str = "hello"
70
+ # str.first #=> "h"
71
+ # str.first(1) #=> "h"
72
+ # str.first(2) #=> "he"
73
+ # str.first(0) #=> ""
74
+ # str.first(6) #=> "hello"
75
+ def first(limit = 1)
76
+ if limit == 0
77
+ ''
78
+ elsif limit >= size
79
+ self
80
+ else
81
+ to(limit - 1)
87
82
  end
83
+ end
88
84
 
89
- def last(limit = 1)
90
- if limit == 0
91
- ''
92
- elsif limit >= size
93
- self
94
- else
95
- from(-limit)
96
- end
85
+ # Returns the last character of the string. If a limit is supplied, returns a substring
86
+ # from the end of the string until it reaches the limit value (counting backwards). If
87
+ # the given limit is greater than or equal to the string length, returns self.
88
+ #
89
+ # str = "hello"
90
+ # str.last #=> "o"
91
+ # str.last(1) #=> "o"
92
+ # str.last(2) #=> "lo"
93
+ # str.last(0) #=> ""
94
+ # str.last(6) #=> "hello"
95
+ def last(limit = 1)
96
+ if limit == 0
97
+ ''
98
+ elsif limit >= size
99
+ self
100
+ else
101
+ from(-limit)
97
102
  end
98
103
  end
99
104
  end
@@ -1,43 +1,36 @@
1
- # encoding: utf-8
2
1
  require 'date'
3
- require 'active_support/core_ext/time/publicize_conversion_methods'
4
2
  require 'active_support/core_ext/time/calculations'
5
3
 
6
4
  class String
7
- # Returns the codepoint of the first character of the string, assuming a
8
- # single-byte character encoding:
5
+ # Converts a string to a Time value.
6
+ # The +form+ can be either :utc or :local (default :local).
9
7
  #
10
- # "a".ord # => 97
11
- # "à".ord # => 224, in ISO-8859-1
8
+ # The time is parsed using Time.parse method.
9
+ # If +form+ is :local, then the time is in the system timezone.
10
+ # If the date part is missing then the current date is used and if
11
+ # the time part is missing then it is assumed to be 00:00:00.
12
12
  #
13
- # This method is defined in Ruby 1.8 for Ruby 1.9 forward compatibility on
14
- # these character encodings.
15
- #
16
- # <tt>ActiveSupport::Multibyte::Chars#ord</tt> is forward compatible with
17
- # Ruby 1.9 on UTF8 strings:
18
- #
19
- # "a".mb_chars.ord # => 97
20
- # "à".mb_chars.ord # => 224, in UTF8
21
- #
22
- # Note that the 224 is different in both examples. In ISO-8859-1 "à" is
23
- # represented as a single byte, 224. In UTF8 it is represented with two
24
- # bytes, namely 195 and 160, but its Unicode codepoint is 224. If we
25
- # call +ord+ on the UTF8 string "à" the return value will be 195. That is
26
- # not an error, because UTF8 is unsupported, the call itself would be
27
- # bogus.
28
- def ord
29
- self[0]
30
- end unless method_defined?(:ord)
13
+ # "13-12-2012".to_time # => 2012-12-13 00:00:00 +0100
14
+ # "06:12".to_time # => 2012-12-13 06:12:00 +0100
15
+ # "2012-12-13 06:12".to_time # => 2012-12-13 06:12:00 +0100
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
18
+ def to_time(form = :local)
19
+ parts = Date._parse(self, false)
20
+ return if parts.empty?
31
21
 
32
- # +getbyte+ backport from Ruby 1.9
33
- alias_method :getbyte, :[] unless method_defined?(:getbyte)
22
+ now = Time.now
23
+ time = Time.new(
24
+ parts.fetch(:year, now.year),
25
+ parts.fetch(:mon, now.month),
26
+ parts.fetch(:mday, now.day),
27
+ parts.fetch(:hour, 0),
28
+ parts.fetch(:min, 0),
29
+ parts.fetch(:sec, 0) + parts.fetch(:sec_fraction, 0),
30
+ parts.fetch(:offset, form == :utc ? 0 : nil)
31
+ )
34
32
 
35
- # Form can be either :utc (default) or :local.
36
- def to_time(form = :utc)
37
- return nil if self.blank?
38
- d = ::Date._parse(self, false).values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction, :offset).map { |arg| arg || 0 }
39
- d[6] *= 1000000
40
- ::Time.send("#{form}_time", *d[0..6]) - d[7]
33
+ form == :utc ? time.utc : time.getlocal
41
34
  end
42
35
 
43
36
  # Converts a string to a Date value.
@@ -47,8 +40,7 @@ class String
47
40
  # "2012-12-13".to_date #=> Thu, 13 Dec 2012
48
41
  # "12/13/2012".to_date #=> ArgumentError: invalid date
49
42
  def to_date
50
- return nil if self.blank?
51
- ::Date.new(*::Date._parse(self, false).values_at(:year, :mon, :mday))
43
+ ::Date.parse(self, false) unless blank?
52
44
  end
53
45
 
54
46
  # Converts a string to a DateTime value.
@@ -58,9 +50,6 @@ class String
58
50
  # "2012-12-13 12:50".to_datetime #=> Thu, 13 Dec 2012 12:50:00 +0000
59
51
  # "12/13/2012".to_datetime #=> ArgumentError: invalid date
60
52
  def to_datetime
61
- return nil if self.blank?
62
- d = ::Date._parse(self, false).values_at(:year, :mon, :mday, :hour, :min, :sec, :zone, :sec_fraction).map { |arg| arg || 0 }
63
- d[5] += d.pop
64
- ::DateTime.civil(*d)
53
+ ::DateTime.parse(self, false) unless blank?
65
54
  end
66
55
  end
@@ -1,11 +1,8 @@
1
+ require 'active_support/deprecation'
2
+
1
3
  class String
2
- if defined?(Encoding) && "".respond_to?(:encode)
3
- def encoding_aware?
4
- true
5
- end
6
- else
7
- def encoding_aware?
8
- false
9
- end
4
+ def encoding_aware?
5
+ ActiveSupport::Deprecation.warn 'String#encoding_aware? is deprecated'
6
+ true
10
7
  end
11
- end
8
+ end
@@ -1,11 +1,10 @@
1
- require 'active_support/core_ext/string/multibyte'
2
-
3
1
  class String
4
2
  # Returns the string, first removing all whitespace on both ends of
5
3
  # the string, and then changing remaining consecutive whitespace
6
4
  # groups into one space each.
7
5
  #
8
- # Examples:
6
+ # Note that it handles both ASCII and Unicode whitespace like mongolian vowel separator (U+180E).
7
+ #
9
8
  # %{ Multi-line
10
9
  # string }.squish # => "Multi-line string"
11
10
  # " foo bar \n \t boo".squish # => "foo bar boo"
@@ -15,35 +14,42 @@ class String
15
14
 
16
15
  # Performs a destructive squish. See String#squish.
17
16
  def squish!
18
- strip!
19
- gsub!(/\s+/, ' ')
17
+ gsub!(/\A[[:space:]]+/, '')
18
+ gsub!(/[[:space:]]+\z/, '')
19
+ gsub!(/[[:space:]]+/, ' ')
20
20
  self
21
21
  end
22
22
 
23
23
  # Truncates a given +text+ after a given <tt>length</tt> if +text+ is longer than <tt>length</tt>:
24
24
  #
25
- # "Once upon a time in a world far far away".truncate(27)
25
+ # 'Once upon a time in a world far far away'.truncate(27)
26
26
  # # => "Once upon a time in a wo..."
27
27
  #
28
- # Pass a <tt>:separator</tt> to truncate +text+ at a natural break:
28
+ # Pass a string or regexp <tt>:separator</tt> to truncate +text+ at a natural break:
29
+ #
30
+ # 'Once upon a time in a world far far away'.truncate(27, separator: ' ')
31
+ # # => "Once upon a time in a..."
29
32
  #
30
- # "Once upon a time in a world far far away".truncate(27, :separator => ' ')
33
+ # 'Once upon a time in a world far far away'.truncate(27, separator: /\s/)
31
34
  # # => "Once upon a time in a..."
32
35
  #
33
36
  # The last characters will be replaced with the <tt>:omission</tt> string (defaults to "...")
34
- # for a total length not exceeding <tt>:length</tt>:
37
+ # for a total length not exceeding <tt>length</tt>:
35
38
  #
36
- # "And they found that many people were sleeping better.".truncate(25, :omission => "... (continued)")
39
+ # 'And they found that many people were sleeping better.'.truncate(25, omission: '... (continued)')
37
40
  # # => "And they f... (continued)"
38
- def truncate(length, options = {})
39
- text = self.dup
40
- options[:omission] ||= "..."
41
+ def truncate(truncate_at, options = {})
42
+ return dup unless length > truncate_at
41
43
 
42
- length_with_room_for_omission = length - options[:omission].mb_chars.length
43
- chars = text.mb_chars
44
- stop = options[:separator] ?
45
- (chars.rindex(options[:separator].mb_chars, length_with_room_for_omission) || length_with_room_for_omission) : length_with_room_for_omission
44
+ options[:omission] ||= '...'
45
+ length_with_room_for_omission = truncate_at - options[:omission].length
46
+ stop = \
47
+ if options[:separator]
48
+ rindex(options[:separator], length_with_room_for_omission) || length_with_room_for_omission
49
+ else
50
+ length_with_room_for_omission
51
+ end
46
52
 
47
- (chars.length > length ? chars[0...stop] + options[:omission] : text).to_s
53
+ "#{self[0...stop]}#{options[:omission]}"
48
54
  end
49
55
  end
@@ -0,0 +1,43 @@
1
+ class String
2
+ # Same as +indent+, except it indents the receiver in-place.
3
+ #
4
+ # Returns the indented string, or +nil+ if there was nothing to indent.
5
+ def indent!(amount, indent_string=nil, indent_empty_lines=false)
6
+ indent_string = indent_string || self[/^[ \t]/] || ' '
7
+ re = indent_empty_lines ? /^/ : /^(?!$)/
8
+ gsub!(re, indent_string * amount)
9
+ end
10
+
11
+ # Indents the lines in the receiver:
12
+ #
13
+ # <<EOS.indent(2)
14
+ # def some_method
15
+ # some_code
16
+ # end
17
+ # EOS
18
+ # # =>
19
+ # def some_method
20
+ # some_code
21
+ # end
22
+ #
23
+ # The second argument, +indent_string+, specifies which indent string to
24
+ # use. The default is +nil+, which tells the method to make a guess by
25
+ # peeking at the first indented line, and fallback to a space if there is
26
+ # none.
27
+ #
28
+ # " foo".indent(2) # => " foo"
29
+ # "foo\n\t\tbar".indent(2) # => "\t\tfoo\n\t\t\t\tbar"
30
+ # "foo".indent(2, "\t") # => "\t\tfoo"
31
+ #
32
+ # While +indent_string+ is typically one space or tab, it may be any string.
33
+ #
34
+ # The third argument, +indent_empty_lines+, is a flag that says whether
35
+ # empty lines should be indented. Default is false.
36
+ #
37
+ # "foo\n\nbar".indent(2) # => " foo\n\n bar"
38
+ # "foo\n\nbar".indent(2, nil, true) # => " foo\n \n bar"
39
+ #
40
+ def indent(amount, indent_string=nil, indent_empty_lines=false)
41
+ dup.tap {|_| _.indent!(amount, indent_string, indent_empty_lines)}
42
+ end
43
+ end