activesupport 3.1.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 (276) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +798 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +13 -7
  5. data/lib/active_support/array_inquirer.rb +44 -0
  6. data/lib/active_support/backtrace_cleaner.rb +38 -34
  7. data/lib/active_support/benchmarkable.rb +17 -28
  8. data/lib/active_support/cache/file_store.rb +85 -70
  9. data/lib/active_support/cache/mem_cache_store.rb +75 -66
  10. data/lib/active_support/cache/memory_store.rb +31 -23
  11. data/lib/active_support/cache/null_store.rb +41 -0
  12. data/lib/active_support/cache/strategy/local_cache.rb +73 -70
  13. data/lib/active_support/cache/strategy/local_cache_middleware.rb +44 -0
  14. data/lib/active_support/cache.rb +360 -294
  15. data/lib/active_support/callbacks.rb +563 -393
  16. data/lib/active_support/concern.rb +42 -34
  17. data/lib/active_support/concurrency/latch.rb +19 -0
  18. data/lib/active_support/concurrency/share_lock.rb +186 -0
  19. data/lib/active_support/configurable.rb +70 -12
  20. data/lib/active_support/core_ext/array/access.rb +53 -9
  21. data/lib/active_support/core_ext/array/conversions.rb +109 -62
  22. data/lib/active_support/core_ext/array/extract_options.rb +2 -2
  23. data/lib/active_support/core_ext/array/grouping.rb +39 -32
  24. data/lib/active_support/core_ext/array/inquiry.rb +17 -0
  25. data/lib/active_support/core_ext/array/prepend_and_append.rb +7 -0
  26. data/lib/active_support/core_ext/array/wrap.rb +16 -18
  27. data/lib/active_support/core_ext/array.rb +2 -2
  28. data/lib/active_support/core_ext/benchmark.rb +7 -0
  29. data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -36
  30. data/lib/active_support/core_ext/class/attribute.rb +47 -34
  31. data/lib/active_support/core_ext/class/attribute_accessors.rb +4 -79
  32. data/lib/active_support/core_ext/class/subclasses.rb +12 -7
  33. data/lib/active_support/core_ext/class.rb +0 -3
  34. data/lib/active_support/core_ext/date/blank.rb +12 -0
  35. data/lib/active_support/core_ext/date/calculations.rb +57 -167
  36. data/lib/active_support/core_ext/date/conversions.rb +31 -42
  37. data/lib/active_support/core_ext/date/zones.rb +2 -10
  38. data/lib/active_support/core_ext/date.rb +5 -0
  39. data/lib/active_support/core_ext/date_and_time/calculations.rb +335 -0
  40. data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -0
  41. data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
  42. data/lib/active_support/core_ext/date_time/acts_like.rb +1 -0
  43. data/lib/active_support/core_ext/date_time/blank.rb +12 -0
  44. data/lib/active_support/core_ext/date_time/calculations.rb +132 -65
  45. data/lib/active_support/core_ext/date_time/compatibility.rb +5 -0
  46. data/lib/active_support/core_ext/date_time/conversions.rb +36 -34
  47. data/lib/active_support/core_ext/date_time.rb +5 -0
  48. data/lib/active_support/core_ext/digest/uuid.rb +51 -0
  49. data/lib/active_support/core_ext/enumerable.rb +81 -74
  50. data/lib/active_support/core_ext/file/atomic.rb +53 -26
  51. data/lib/active_support/core_ext/file.rb +0 -1
  52. data/lib/active_support/core_ext/hash/compact.rb +20 -0
  53. data/lib/active_support/core_ext/hash/conversions.rb +175 -70
  54. data/lib/active_support/core_ext/hash/deep_merge.rb +30 -8
  55. data/lib/active_support/core_ext/hash/except.rb +11 -12
  56. data/lib/active_support/core_ext/hash/indifferent_access.rb +7 -8
  57. data/lib/active_support/core_ext/hash/keys.rb +147 -24
  58. data/lib/active_support/core_ext/hash/reverse_merge.rb +2 -3
  59. data/lib/active_support/core_ext/hash/slice.rb +22 -14
  60. data/lib/active_support/core_ext/hash/transform_values.rb +29 -0
  61. data/lib/active_support/core_ext/hash.rb +2 -2
  62. data/lib/active_support/core_ext/integer/inflections.rb +13 -1
  63. data/lib/active_support/core_ext/integer/multiple.rb +4 -0
  64. data/lib/active_support/core_ext/integer/time.rb +12 -22
  65. data/lib/active_support/core_ext/kernel/agnostics.rb +2 -2
  66. data/lib/active_support/core_ext/kernel/concern.rb +12 -0
  67. data/lib/active_support/core_ext/kernel/debugger.rb +2 -15
  68. data/lib/active_support/core_ext/kernel/reporting.rb +12 -62
  69. data/lib/active_support/core_ext/kernel/singleton_class.rb +0 -7
  70. data/lib/active_support/core_ext/kernel.rb +2 -3
  71. data/lib/active_support/core_ext/load_error.rb +14 -7
  72. data/lib/active_support/core_ext/marshal.rb +22 -0
  73. data/lib/active_support/core_ext/module/aliasing.rb +16 -12
  74. data/lib/active_support/core_ext/module/anonymous.rb +12 -8
  75. data/lib/active_support/core_ext/module/attr_internal.rb +2 -5
  76. data/lib/active_support/core_ext/module/attribute_accessors.rb +165 -13
  77. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +141 -0
  78. data/lib/active_support/core_ext/module/concerning.rb +135 -0
  79. data/lib/active_support/core_ext/module/delegation.rb +141 -68
  80. data/lib/active_support/core_ext/module/deprecation.rb +17 -3
  81. data/lib/active_support/core_ext/module/introspection.rb +9 -31
  82. data/lib/active_support/core_ext/module/method_transplanting.rb +3 -0
  83. data/lib/active_support/core_ext/module/qualified_const.rb +70 -0
  84. data/lib/active_support/core_ext/module/reachable.rb +1 -3
  85. data/lib/active_support/core_ext/module/remove_method.rb +24 -5
  86. data/lib/active_support/core_ext/module.rb +3 -3
  87. data/lib/active_support/core_ext/name_error.rb +15 -2
  88. data/lib/active_support/core_ext/numeric/bytes.rb +20 -0
  89. data/lib/active_support/core_ext/numeric/conversions.rb +145 -0
  90. data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
  91. data/lib/active_support/core_ext/numeric/time.rb +31 -36
  92. data/lib/active_support/core_ext/numeric.rb +2 -0
  93. data/lib/active_support/core_ext/object/acts_like.rb +4 -4
  94. data/lib/active_support/core_ext/object/blank.rb +52 -18
  95. data/lib/active_support/core_ext/object/deep_dup.rb +53 -0
  96. data/lib/active_support/core_ext/object/duplicable.rb +12 -20
  97. data/lib/active_support/core_ext/object/inclusion.rb +13 -1
  98. data/lib/active_support/core_ext/object/instance_variables.rb +7 -12
  99. data/lib/active_support/core_ext/object/json.rb +205 -0
  100. data/lib/active_support/core_ext/object/to_param.rb +1 -55
  101. data/lib/active_support/core_ext/object/to_query.rb +66 -9
  102. data/lib/active_support/core_ext/object/try.rb +124 -33
  103. data/lib/active_support/core_ext/object/with_options.rb +37 -11
  104. data/lib/active_support/core_ext/object.rb +2 -1
  105. data/lib/active_support/core_ext/range/conversions.rb +17 -7
  106. data/lib/active_support/core_ext/range/each.rb +21 -0
  107. data/lib/active_support/core_ext/range/include_range.rb +20 -18
  108. data/lib/active_support/core_ext/range/overlaps.rb +1 -1
  109. data/lib/active_support/core_ext/range.rb +1 -2
  110. data/lib/active_support/core_ext/securerandom.rb +23 -0
  111. data/lib/active_support/core_ext/string/access.rb +95 -90
  112. data/lib/active_support/core_ext/string/behavior.rb +1 -1
  113. data/lib/active_support/core_ext/string/conversions.rb +41 -38
  114. data/lib/active_support/core_ext/string/exclude.rb +6 -1
  115. data/lib/active_support/core_ext/string/filters.rb +70 -17
  116. data/lib/active_support/core_ext/string/indent.rb +43 -0
  117. data/lib/active_support/core_ext/string/inflections.rb +139 -59
  118. data/lib/active_support/core_ext/string/inquiry.rb +2 -2
  119. data/lib/active_support/core_ext/string/multibyte.rb +46 -65
  120. data/lib/active_support/core_ext/string/output_safety.rb +153 -56
  121. data/lib/active_support/core_ext/string/strip.rb +3 -6
  122. data/lib/active_support/core_ext/string/zones.rb +14 -0
  123. data/lib/active_support/core_ext/string.rb +2 -3
  124. data/lib/active_support/core_ext/struct.rb +3 -0
  125. data/lib/active_support/core_ext/time/calculations.rb +173 -173
  126. data/lib/active_support/core_ext/time/compatibility.rb +5 -0
  127. data/lib/active_support/core_ext/time/conversions.rb +33 -29
  128. data/lib/active_support/core_ext/time/marshal.rb +2 -56
  129. data/lib/active_support/core_ext/time/zones.rb +57 -32
  130. data/lib/active_support/core_ext/time.rb +5 -0
  131. data/lib/active_support/core_ext/uri.rb +13 -19
  132. data/lib/active_support/core_ext.rb +3 -2
  133. data/lib/active_support/dependencies/autoload.rb +47 -20
  134. data/lib/active_support/dependencies/interlock.rb +51 -0
  135. data/lib/active_support/dependencies.rb +315 -265
  136. data/lib/active_support/deprecation/behaviors.rb +71 -30
  137. data/lib/active_support/deprecation/instance_delegator.rb +24 -0
  138. data/lib/active_support/deprecation/method_wrappers.rb +59 -18
  139. data/lib/active_support/deprecation/proxy_wrappers.rb +82 -14
  140. data/lib/active_support/deprecation/reporting.rb +61 -14
  141. data/lib/active_support/deprecation.rb +38 -13
  142. data/lib/active_support/descendants_tracker.rb +34 -19
  143. data/lib/active_support/duration/iso8601_parser.rb +122 -0
  144. data/lib/active_support/duration/iso8601_serializer.rb +51 -0
  145. data/lib/active_support/duration.rb +85 -14
  146. data/lib/active_support/evented_file_update_checker.rb +194 -0
  147. data/lib/active_support/execution_wrapper.rb +117 -0
  148. data/lib/active_support/executor.rb +6 -0
  149. data/lib/active_support/file_update_checker.rb +138 -17
  150. data/lib/active_support/gem_version.rb +15 -0
  151. data/lib/active_support/gzip.rb +11 -5
  152. data/lib/active_support/hash_with_indifferent_access.rb +199 -49
  153. data/lib/active_support/i18n.rb +6 -2
  154. data/lib/active_support/i18n_railtie.rb +40 -21
  155. data/lib/active_support/inflections.rb +22 -13
  156. data/lib/active_support/inflector/inflections.rb +175 -144
  157. data/lib/active_support/inflector/methods.rb +328 -91
  158. data/lib/active_support/inflector/transliterate.rb +51 -37
  159. data/lib/active_support/json/decoding.rb +31 -22
  160. data/lib/active_support/json/encoding.rb +88 -248
  161. data/lib/active_support/key_generator.rb +71 -0
  162. data/lib/active_support/lazy_load_hooks.rb +27 -25
  163. data/lib/active_support/locale/en.yml +102 -3
  164. data/lib/active_support/log_subscriber/test_helper.rb +24 -21
  165. data/lib/active_support/log_subscriber.rb +36 -49
  166. data/lib/active_support/logger.rb +106 -0
  167. data/lib/active_support/logger_silence.rb +28 -0
  168. data/lib/active_support/logger_thread_safe_level.rb +31 -0
  169. data/lib/active_support/message_encryptor.rb +72 -36
  170. data/lib/active_support/message_verifier.rb +96 -24
  171. data/lib/active_support/multibyte/chars.rb +88 -333
  172. data/lib/active_support/multibyte/unicode.rb +156 -136
  173. data/lib/active_support/multibyte.rb +5 -28
  174. data/lib/active_support/notifications/fanout.rb +115 -19
  175. data/lib/active_support/notifications/instrumenter.rb +52 -15
  176. data/lib/active_support/notifications.rb +168 -33
  177. data/lib/active_support/number_helper/number_converter.rb +182 -0
  178. data/lib/active_support/number_helper/number_to_currency_converter.rb +44 -0
  179. data/lib/active_support/number_helper/number_to_delimited_converter.rb +28 -0
  180. data/lib/active_support/number_helper/number_to_human_converter.rb +68 -0
  181. data/lib/active_support/number_helper/number_to_human_size_converter.rb +62 -0
  182. data/lib/active_support/number_helper/number_to_percentage_converter.rb +12 -0
  183. data/lib/active_support/number_helper/number_to_phone_converter.rb +58 -0
  184. data/lib/active_support/number_helper/number_to_rounded_converter.rb +92 -0
  185. data/lib/active_support/number_helper.rb +368 -0
  186. data/lib/active_support/option_merger.rb +1 -1
  187. data/lib/active_support/ordered_hash.rb +18 -183
  188. data/lib/active_support/ordered_options.rb +44 -24
  189. data/lib/active_support/per_thread_registry.rb +58 -0
  190. data/lib/active_support/proxy_object.rb +13 -0
  191. data/lib/active_support/rails.rb +27 -0
  192. data/lib/active_support/railtie.rb +25 -34
  193. data/lib/active_support/reloader.rb +129 -0
  194. data/lib/active_support/rescuable.rb +98 -48
  195. data/lib/active_support/security_utils.rb +27 -0
  196. data/lib/active_support/string_inquirer.rb +14 -9
  197. data/lib/active_support/subscriber.rb +120 -0
  198. data/lib/active_support/tagged_logging.rb +78 -0
  199. data/lib/active_support/test_case.rb +69 -17
  200. data/lib/active_support/testing/assertions.rb +43 -41
  201. data/lib/active_support/testing/autorun.rb +12 -0
  202. data/lib/active_support/testing/constant_lookup.rb +50 -0
  203. data/lib/active_support/testing/declarative.rb +7 -21
  204. data/lib/active_support/testing/deprecation.rb +14 -33
  205. data/lib/active_support/testing/file_fixtures.rb +34 -0
  206. data/lib/active_support/testing/isolation.rb +53 -95
  207. data/lib/active_support/testing/method_call_assertions.rb +41 -0
  208. data/lib/active_support/testing/setup_and_teardown.rb +21 -82
  209. data/lib/active_support/testing/stream.rb +42 -0
  210. data/lib/active_support/testing/tagged_logging.rb +25 -0
  211. data/lib/active_support/testing/time_helpers.rb +134 -0
  212. data/lib/active_support/time.rb +6 -23
  213. data/lib/active_support/time_with_zone.rb +239 -92
  214. data/lib/active_support/values/time_zone.rb +236 -160
  215. data/lib/active_support/values/unicode_tables.dat +0 -0
  216. data/lib/active_support/version.rb +5 -7
  217. data/lib/active_support/xml_mini/jdom.rb +19 -13
  218. data/lib/active_support/xml_mini/libxml.rb +3 -4
  219. data/lib/active_support/xml_mini/libxmlsax.rb +2 -3
  220. data/lib/active_support/xml_mini/nokogiri.rb +3 -4
  221. data/lib/active_support/xml_mini/nokogirisax.rb +2 -3
  222. data/lib/active_support/xml_mini/rexml.rb +8 -10
  223. data/lib/active_support/xml_mini.rb +66 -34
  224. data/lib/active_support.rb +40 -23
  225. metadata +185 -134
  226. data/CHANGELOG +0 -1534
  227. data/lib/active_support/base64.rb +0 -42
  228. data/lib/active_support/basic_object.rb +0 -21
  229. data/lib/active_support/buffered_logger.rb +0 -137
  230. data/lib/active_support/cache/compressed_mem_cache_store.rb +0 -13
  231. data/lib/active_support/cache/synchronized_memory_store.rb +0 -11
  232. data/lib/active_support/core_ext/array/random_access.rb +0 -30
  233. data/lib/active_support/core_ext/array/uniq_by.rb +0 -16
  234. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -44
  235. data/lib/active_support/core_ext/class/inheritable_attributes.rb +0 -178
  236. data/lib/active_support/core_ext/date/freeze.rb +0 -31
  237. data/lib/active_support/core_ext/date_time/zones.rb +0 -21
  238. data/lib/active_support/core_ext/exception.rb +0 -3
  239. data/lib/active_support/core_ext/file/path.rb +0 -5
  240. data/lib/active_support/core_ext/float/rounding.rb +0 -19
  241. data/lib/active_support/core_ext/float.rb +0 -1
  242. data/lib/active_support/core_ext/hash/deep_dup.rb +0 -11
  243. data/lib/active_support/core_ext/hash/diff.rb +0 -13
  244. data/lib/active_support/core_ext/kernel/requires.rb +0 -28
  245. data/lib/active_support/core_ext/logger.rb +0 -81
  246. data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +0 -31
  247. data/lib/active_support/core_ext/module/method_names.rb +0 -14
  248. data/lib/active_support/core_ext/module/synchronization.rb +0 -43
  249. data/lib/active_support/core_ext/object/to_json.rb +0 -19
  250. data/lib/active_support/core_ext/proc.rb +0 -14
  251. data/lib/active_support/core_ext/process/daemon.rb +0 -23
  252. data/lib/active_support/core_ext/process.rb +0 -1
  253. data/lib/active_support/core_ext/range/blockless_step.rb +0 -29
  254. data/lib/active_support/core_ext/range/cover.rb +0 -3
  255. data/lib/active_support/core_ext/rexml.rb +0 -46
  256. data/lib/active_support/core_ext/string/encoding.rb +0 -11
  257. data/lib/active_support/core_ext/string/interpolation.rb +0 -2
  258. data/lib/active_support/core_ext/string/xchar.rb +0 -18
  259. data/lib/active_support/core_ext/time/publicize_conversion_methods.rb +0 -10
  260. data/lib/active_support/file_watcher.rb +0 -36
  261. data/lib/active_support/json/variable.rb +0 -9
  262. data/lib/active_support/memoizable.rb +0 -105
  263. data/lib/active_support/multibyte/exceptions.rb +0 -8
  264. data/lib/active_support/multibyte/utils.rb +0 -60
  265. data/lib/active_support/ruby/shim.rb +0 -22
  266. data/lib/active_support/secure_random.rb +0 -6
  267. data/lib/active_support/testing/mochaing.rb +0 -7
  268. data/lib/active_support/testing/pending.rb +0 -52
  269. data/lib/active_support/testing/performance/jruby.rb +0 -115
  270. data/lib/active_support/testing/performance/rubinius.rb +0 -113
  271. data/lib/active_support/testing/performance/ruby/mri.rb +0 -57
  272. data/lib/active_support/testing/performance/ruby/yarv.rb +0 -57
  273. data/lib/active_support/testing/performance/ruby.rb +0 -152
  274. data/lib/active_support/testing/performance.rb +0 -317
  275. data/lib/active_support/time/autoload.rb +0 -5
  276. data/lib/active_support/whiny_nil.rb +0 -60
@@ -1,21 +1,23 @@
1
- class Range
2
- # Extends the default Range#include? to support range comparisons.
3
- # (1..5).include?(1..5) # => true
4
- # (1..5).include?(2..3) # => true
5
- # (1..5).include?(2..6) # => false
6
- #
7
- # The native Range#include? behavior is untouched.
8
- # ("a".."f").include?("c") # => true
9
- # (5..9).include?(11) # => false
10
- def include_with_range?(value)
11
- if value.is_a?(::Range)
12
- operator = exclude_end? ? :< : :<=
13
- end_value = value.exclude_end? ? last.succ : last
14
- include_without_range?(value.first) && (value.last <=> end_value).send(operator, 0)
15
- else
16
- 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
17
19
  end
18
20
  end
19
-
20
- alias_method_chain :include?, :range
21
21
  end
22
+
23
+ Range.prepend(ActiveSupport::IncludeWithRange)
@@ -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,4 @@
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'
4
+ require 'active_support/core_ext/range/each'
@@ -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,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 integer, 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 a copy of 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.dup
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 a copy of 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.dup
100
+ else
101
+ from(-limit)
97
102
  end
98
103
  end
99
104
  end
@@ -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
@@ -1,54 +1,57 @@
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 06:12:00 UTC
18
+ # "12/13/2012".to_time # => ArgumentError: argument out of range
19
+ def to_time(form = :local)
20
+ parts = Date._parse(self, false)
21
+ used_keys = %i(year mon mday hour min sec sec_fraction offset)
22
+ return if (parts.keys & used_keys).empty?
31
23
 
32
- # +getbyte+ backport from Ruby 1.9
33
- alias_method :getbyte, :[] unless method_defined?(:getbyte)
24
+ now = Time.now
25
+ time = Time.new(
26
+ parts.fetch(:year, now.year),
27
+ parts.fetch(:mon, now.month),
28
+ parts.fetch(:mday, now.day),
29
+ parts.fetch(:hour, 0),
30
+ parts.fetch(:min, 0),
31
+ parts.fetch(:sec, 0) + parts.fetch(:sec_fraction, 0),
32
+ parts.fetch(:offset, form == :utc ? 0 : nil)
33
+ )
34
34
 
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).map { |arg| arg || 0 }
39
- d[6] *= 1000000
40
- ::Time.send("#{form}_time", *d)
35
+ form == :utc ? time.utc : time.to_time
41
36
  end
42
37
 
38
+ # Converts a string to a Date value.
39
+ #
40
+ # "1-1-2012".to_date # => Sun, 01 Jan 2012
41
+ # "01/01/2012".to_date # => Sun, 01 Jan 2012
42
+ # "2012-12-13".to_date # => Thu, 13 Dec 2012
43
+ # "12/13/2012".to_date # => ArgumentError: invalid date
43
44
  def to_date
44
- return nil if self.blank?
45
- ::Date.new(*::Date._parse(self, false).values_at(:year, :mon, :mday))
45
+ ::Date.parse(self, false) unless blank?
46
46
  end
47
47
 
48
+ # Converts a string to a DateTime value.
49
+ #
50
+ # "1-1-2012".to_datetime # => Sun, 01 Jan 2012 00:00:00 +0000
51
+ # "01/01/2012 23:59:59".to_datetime # => Sun, 01 Jan 2012 23:59:59 +0000
52
+ # "2012-12-13 12:50".to_datetime # => Thu, 13 Dec 2012 12:50:00 +0000
53
+ # "12/13/2012".to_datetime # => ArgumentError: invalid date
48
54
  def to_datetime
49
- return nil if self.blank?
50
- d = ::Date._parse(self, false).values_at(:year, :mon, :mday, :hour, :min, :sec, :zone, :sec_fraction).map { |arg| arg || 0 }
51
- d[5] += d.pop
52
- ::DateTime.civil(*d)
55
+ ::DateTime.parse(self, false) unless blank?
53
56
  end
54
57
  end
@@ -1,5 +1,10 @@
1
1
  class String
2
- # The inverse of <tt>String#include?</tt>. Returns true if the string does not include the other string.
2
+ # The inverse of <tt>String#include?</tt>. Returns true if the string
3
+ # does not include the other string.
4
+ #
5
+ # "hello".exclude? "lo" # => false
6
+ # "hello".exclude? "ol" # => true
7
+ # "hello".exclude? ?h # => false
3
8
  def exclude?(string)
4
9
  !include?(string)
5
10
  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.
7
+ #
9
8
  # %{ Multi-line
10
9
  # string }.squish # => "Multi-line string"
11
10
  # " foo bar \n \t boo".squish # => "foo bar boo"
@@ -14,36 +13,90 @@ class String
14
13
  end
15
14
 
16
15
  # Performs a destructive squish. See String#squish.
16
+ # str = " foo bar \n \t boo"
17
+ # str.squish! # => "foo bar boo"
18
+ # str # => "foo bar boo"
17
19
  def squish!
20
+ gsub!(/[[:space:]]+/, ' ')
18
21
  strip!
19
- gsub!(/\s+/, ' ')
22
+ self
23
+ end
24
+
25
+ # Returns a new string with all occurrences of the patterns removed.
26
+ # str = "foo bar test"
27
+ # str.remove(" test") # => "foo bar"
28
+ # str.remove(" test", /bar/) # => "foo "
29
+ # str # => "foo bar test"
30
+ def remove(*patterns)
31
+ dup.remove!(*patterns)
32
+ end
33
+
34
+ # Alters the string by removing all occurrences of the patterns.
35
+ # str = "foo bar test"
36
+ # str.remove!(" test", /bar/) # => "foo "
37
+ # str # => "foo "
38
+ def remove!(*patterns)
39
+ patterns.each do |pattern|
40
+ gsub! pattern, ""
41
+ end
42
+
20
43
  self
21
44
  end
22
45
 
23
46
  # Truncates a given +text+ after a given <tt>length</tt> if +text+ is longer than <tt>length</tt>:
24
47
  #
25
- # "Once upon a time in a world far far away".truncate(27)
48
+ # 'Once upon a time in a world far far away'.truncate(27)
26
49
  # # => "Once upon a time in a wo..."
27
50
  #
28
- # Pass a <tt>:separator</tt> to truncate +text+ at a natural break:
51
+ # Pass a string or regexp <tt>:separator</tt> to truncate +text+ at a natural break:
29
52
  #
30
- # "Once upon a time in a world far far away".truncate(27, :separator => ' ')
53
+ # 'Once upon a time in a world far far away'.truncate(27, separator: ' ')
54
+ # # => "Once upon a time in a..."
55
+ #
56
+ # 'Once upon a time in a world far far away'.truncate(27, separator: /\s/)
31
57
  # # => "Once upon a time in a..."
32
58
  #
33
59
  # The last characters will be replaced with the <tt>:omission</tt> string (defaults to "...")
34
- # for a total length not exceeding <tt>:length</tt>:
60
+ # for a total length not exceeding <tt>length</tt>:
35
61
  #
36
- # "And they found that many people were sleeping better.".truncate(25, :omission => "... (continued)")
62
+ # 'And they found that many people were sleeping better.'.truncate(25, omission: '... (continued)')
37
63
  # # => "And they f... (continued)"
38
- def truncate(length, options = {})
39
- text = self.dup
40
- options[:omission] ||= "..."
64
+ def truncate(truncate_at, options = {})
65
+ return dup unless length > truncate_at
66
+
67
+ omission = options[:omission] || '...'
68
+ length_with_room_for_omission = truncate_at - omission.length
69
+ stop = \
70
+ if options[:separator]
71
+ rindex(options[:separator], length_with_room_for_omission) || length_with_room_for_omission
72
+ else
73
+ length_with_room_for_omission
74
+ end
41
75
 
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
76
+ "#{self[0, stop]}#{omission}"
77
+ end
46
78
 
47
- (chars.length > length ? chars[0...stop] + options[:omission] : text).to_s
79
+ # Truncates a given +text+ after a given number of words (<tt>words_count</tt>):
80
+ #
81
+ # 'Once upon a time in a world far far away'.truncate_words(4)
82
+ # # => "Once upon a time..."
83
+ #
84
+ # Pass a string or regexp <tt>:separator</tt> to specify a different separator of words:
85
+ #
86
+ # 'Once<br>upon<br>a<br>time<br>in<br>a<br>world'.truncate_words(5, separator: '<br>')
87
+ # # => "Once<br>upon<br>a<br>time<br>in..."
88
+ #
89
+ # The last characters will be replaced with the <tt>:omission</tt> string (defaults to "..."):
90
+ #
91
+ # 'And they found that many people were sleeping better.'.truncate_words(5, omission: '... (continued)')
92
+ # # => "And they found that many... (continued)"
93
+ def truncate_words(words_count, options = {})
94
+ sep = options[:separator] || /\s+/
95
+ sep = Regexp.escape(sep.to_s) unless Regexp === sep
96
+ if self =~ /\A((?>.+?#{sep}){#{words_count - 1}}.+?)#{sep}.*/m
97
+ $1 + (options[:omission] || '...')
98
+ else
99
+ dup
100
+ end
48
101
  end
49
102
  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