activesupport 1.2.4 → 8.1.2

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 (309) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +505 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +40 -0
  5. data/lib/active_support/actionable_error.rb +50 -0
  6. data/lib/active_support/all.rb +5 -0
  7. data/lib/active_support/array_inquirer.rb +50 -0
  8. data/lib/active_support/backtrace_cleaner.rb +234 -0
  9. data/lib/active_support/benchmark.rb +21 -0
  10. data/lib/active_support/benchmarkable.rb +53 -0
  11. data/lib/active_support/broadcast_logger.rb +238 -0
  12. data/lib/active_support/builder.rb +8 -0
  13. data/lib/active_support/cache/coder.rb +153 -0
  14. data/lib/active_support/cache/entry.rb +134 -0
  15. data/lib/active_support/cache/file_store.rb +244 -0
  16. data/lib/active_support/cache/mem_cache_store.rb +288 -0
  17. data/lib/active_support/cache/memory_store.rb +264 -0
  18. data/lib/active_support/cache/null_store.rb +62 -0
  19. data/lib/active_support/cache/redis_cache_store.rb +498 -0
  20. data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
  21. data/lib/active_support/cache/strategy/local_cache.rb +246 -0
  22. data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
  23. data/lib/active_support/cache.rb +1170 -0
  24. data/lib/active_support/callbacks.rb +960 -0
  25. data/lib/active_support/class_attribute.rb +33 -0
  26. data/lib/active_support/code_generator.rb +79 -0
  27. data/lib/active_support/concern.rb +217 -0
  28. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
  29. data/lib/active_support/concurrency/null_lock.rb +13 -0
  30. data/lib/active_support/concurrency/share_lock.rb +225 -0
  31. data/lib/active_support/concurrency/thread_monitor.rb +55 -0
  32. data/lib/active_support/configurable.rb +193 -0
  33. data/lib/active_support/configuration_file.rb +60 -0
  34. data/lib/active_support/continuous_integration.rb +145 -0
  35. data/lib/active_support/core_ext/array/access.rb +100 -0
  36. data/lib/active_support/core_ext/array/conversions.rb +209 -26
  37. data/lib/active_support/core_ext/array/extract.rb +21 -0
  38. data/lib/active_support/core_ext/array/extract_options.rb +31 -0
  39. data/lib/active_support/core_ext/array/grouping.rb +109 -0
  40. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  41. data/lib/active_support/core_ext/array/wrap.rb +48 -0
  42. data/lib/active_support/core_ext/array.rb +8 -4
  43. data/lib/active_support/core_ext/benchmark.rb +6 -0
  44. data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
  45. data/lib/active_support/core_ext/big_decimal.rb +3 -0
  46. data/lib/active_support/core_ext/class/attribute.rb +137 -0
  47. data/lib/active_support/core_ext/class/attribute_accessors.rb +6 -0
  48. data/lib/active_support/core_ext/class/subclasses.rb +24 -0
  49. data/lib/active_support/core_ext/class.rb +4 -0
  50. data/lib/active_support/core_ext/date/acts_like.rb +10 -0
  51. data/lib/active_support/core_ext/date/blank.rb +18 -0
  52. data/lib/active_support/core_ext/date/calculations.rb +161 -0
  53. data/lib/active_support/core_ext/date/conversions.rb +95 -28
  54. data/lib/active_support/core_ext/date/zones.rb +8 -0
  55. data/lib/active_support/core_ext/date.rb +6 -5
  56. data/lib/active_support/core_ext/date_and_time/calculations.rb +374 -0
  57. data/lib/active_support/core_ext/date_and_time/compatibility.rb +23 -0
  58. data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
  59. data/lib/active_support/core_ext/date_time/acts_like.rb +16 -0
  60. data/lib/active_support/core_ext/date_time/blank.rb +18 -0
  61. data/lib/active_support/core_ext/date_time/calculations.rb +215 -0
  62. data/lib/active_support/core_ext/date_time/compatibility.rb +16 -0
  63. data/lib/active_support/core_ext/date_time/conversions.rb +108 -0
  64. data/lib/active_support/core_ext/date_time.rb +7 -0
  65. data/lib/active_support/core_ext/digest/uuid.rb +76 -0
  66. data/lib/active_support/core_ext/digest.rb +3 -0
  67. data/lib/active_support/core_ext/enumerable.rb +277 -7
  68. data/lib/active_support/core_ext/erb/util.rb +201 -0
  69. data/lib/active_support/core_ext/file/atomic.rb +72 -0
  70. data/lib/active_support/core_ext/file.rb +3 -0
  71. data/lib/active_support/core_ext/hash/conversions.rb +262 -0
  72. data/lib/active_support/core_ext/hash/deep_merge.rb +43 -0
  73. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  74. data/lib/active_support/core_ext/hash/except.rb +12 -0
  75. data/lib/active_support/core_ext/hash/indifferent_access.rb +19 -55
  76. data/lib/active_support/core_ext/hash/keys.rb +134 -44
  77. data/lib/active_support/core_ext/hash/reverse_merge.rb +22 -22
  78. data/lib/active_support/core_ext/hash/slice.rb +27 -0
  79. data/lib/active_support/core_ext/hash.rb +9 -8
  80. data/lib/active_support/core_ext/integer/inflections.rb +29 -13
  81. data/lib/active_support/core_ext/integer/multiple.rb +12 -0
  82. data/lib/active_support/core_ext/integer/time.rb +22 -0
  83. data/lib/active_support/core_ext/integer.rb +4 -6
  84. data/lib/active_support/core_ext/kernel/concern.rb +14 -0
  85. data/lib/active_support/core_ext/kernel/reporting.rb +45 -0
  86. data/lib/active_support/core_ext/kernel/singleton_class.rb +8 -0
  87. data/lib/active_support/core_ext/kernel.rb +4 -78
  88. data/lib/active_support/core_ext/load_error.rb +6 -35
  89. data/lib/active_support/core_ext/module/aliasing.rb +31 -0
  90. data/lib/active_support/core_ext/module/anonymous.rb +30 -0
  91. data/lib/active_support/core_ext/module/attr_internal.rb +48 -0
  92. data/lib/active_support/core_ext/module/attribute_accessors.rb +214 -0
  93. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +175 -0
  94. data/lib/active_support/core_ext/module/concerning.rb +140 -0
  95. data/lib/active_support/core_ext/module/delegation.rb +225 -0
  96. data/lib/active_support/core_ext/module/deprecation.rb +25 -0
  97. data/lib/active_support/core_ext/module/introspection.rb +65 -0
  98. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  99. data/lib/active_support/core_ext/module/remove_method.rb +17 -0
  100. data/lib/active_support/core_ext/module.rb +13 -0
  101. data/lib/active_support/core_ext/name_error.rb +59 -0
  102. data/lib/active_support/core_ext/numeric/bytes.rb +73 -42
  103. data/lib/active_support/core_ext/numeric/conversions.rb +145 -0
  104. data/lib/active_support/core_ext/numeric/time.rb +64 -57
  105. data/lib/active_support/core_ext/numeric.rb +4 -6
  106. data/lib/active_support/core_ext/object/acts_like.rb +45 -0
  107. data/lib/active_support/core_ext/object/blank.rb +199 -0
  108. data/lib/active_support/core_ext/object/conversions.rb +6 -0
  109. data/lib/active_support/core_ext/object/deep_dup.rb +71 -0
  110. data/lib/active_support/core_ext/object/duplicable.rb +69 -0
  111. data/lib/active_support/core_ext/object/inclusion.rb +37 -0
  112. data/lib/active_support/core_ext/object/instance_variables.rb +32 -0
  113. data/lib/active_support/core_ext/object/json.rb +267 -0
  114. data/lib/active_support/core_ext/object/to_param.rb +3 -0
  115. data/lib/active_support/core_ext/object/to_query.rb +93 -0
  116. data/lib/active_support/core_ext/object/try.rb +158 -0
  117. data/lib/active_support/core_ext/object/with.rb +46 -0
  118. data/lib/active_support/core_ext/object/with_options.rb +101 -0
  119. data/lib/active_support/core_ext/object.rb +17 -0
  120. data/lib/active_support/core_ext/pathname/blank.rb +20 -0
  121. data/lib/active_support/core_ext/pathname/existence.rb +23 -0
  122. data/lib/active_support/core_ext/pathname.rb +4 -0
  123. data/lib/active_support/core_ext/range/compare_range.rb +57 -0
  124. data/lib/active_support/core_ext/range/conversions.rb +58 -17
  125. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  126. data/lib/active_support/core_ext/range/sole.rb +17 -0
  127. data/lib/active_support/core_ext/range.rb +5 -4
  128. data/lib/active_support/core_ext/regexp.rb +14 -0
  129. data/lib/active_support/core_ext/securerandom.rb +57 -0
  130. data/lib/active_support/core_ext/string/access.rb +93 -56
  131. data/lib/active_support/core_ext/string/behavior.rb +8 -0
  132. data/lib/active_support/core_ext/string/conversions.rb +57 -16
  133. data/lib/active_support/core_ext/string/exclude.rb +13 -0
  134. data/lib/active_support/core_ext/string/filters.rb +151 -0
  135. data/lib/active_support/core_ext/string/indent.rb +45 -0
  136. data/lib/active_support/core_ext/string/inflections.rb +297 -54
  137. data/lib/active_support/core_ext/string/inquiry.rb +16 -0
  138. data/lib/active_support/core_ext/string/multibyte.rb +67 -0
  139. data/lib/active_support/core_ext/string/output_safety.rb +235 -0
  140. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -18
  141. data/lib/active_support/core_ext/string/strip.rb +27 -0
  142. data/lib/active_support/core_ext/string/zones.rb +16 -0
  143. data/lib/active_support/core_ext/string.rb +14 -10
  144. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  145. data/lib/active_support/core_ext/symbol.rb +3 -0
  146. data/lib/active_support/core_ext/thread/backtrace/location.rb +7 -0
  147. data/lib/active_support/core_ext/time/acts_like.rb +10 -0
  148. data/lib/active_support/core_ext/time/calculations.rb +358 -153
  149. data/lib/active_support/core_ext/time/compatibility.rb +15 -0
  150. data/lib/active_support/core_ext/time/conversions.rb +69 -30
  151. data/lib/active_support/core_ext/time/zones.rb +97 -0
  152. data/lib/active_support/core_ext/time.rb +6 -6
  153. data/lib/active_support/core_ext.rb +5 -1
  154. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  155. data/lib/active_support/current_attributes.rb +243 -0
  156. data/lib/active_support/deep_mergeable.rb +53 -0
  157. data/lib/active_support/delegation.rb +183 -0
  158. data/lib/active_support/dependencies/autoload.rb +72 -0
  159. data/lib/active_support/dependencies/interlock.rb +55 -0
  160. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  161. data/lib/active_support/dependencies.rb +84 -222
  162. data/lib/active_support/deprecation/behaviors.rb +148 -0
  163. data/lib/active_support/deprecation/constant_accessor.rb +74 -0
  164. data/lib/active_support/deprecation/deprecators.rb +104 -0
  165. data/lib/active_support/deprecation/disallowed.rb +54 -0
  166. data/lib/active_support/deprecation/method_wrappers.rb +68 -0
  167. data/lib/active_support/deprecation/proxy_wrappers.rb +189 -0
  168. data/lib/active_support/deprecation/reporting.rb +162 -0
  169. data/lib/active_support/deprecation.rb +81 -0
  170. data/lib/active_support/deprecator.rb +7 -0
  171. data/lib/active_support/descendants_tracker.rb +112 -0
  172. data/lib/active_support/digest.rb +22 -0
  173. data/lib/active_support/duration/iso8601_parser.rb +123 -0
  174. data/lib/active_support/duration/iso8601_serializer.rb +64 -0
  175. data/lib/active_support/duration.rb +524 -0
  176. data/lib/active_support/editor.rb +70 -0
  177. data/lib/active_support/encrypted_configuration.rb +126 -0
  178. data/lib/active_support/encrypted_file.rb +133 -0
  179. data/lib/active_support/environment_inquirer.rb +40 -0
  180. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  181. data/lib/active_support/error_reporter.rb +318 -0
  182. data/lib/active_support/event_reporter/test_helper.rb +32 -0
  183. data/lib/active_support/event_reporter.rb +592 -0
  184. data/lib/active_support/evented_file_update_checker.rb +185 -0
  185. data/lib/active_support/execution_context/test_helper.rb +13 -0
  186. data/lib/active_support/execution_context.rb +110 -0
  187. data/lib/active_support/execution_wrapper.rb +150 -0
  188. data/lib/active_support/executor/test_helper.rb +7 -0
  189. data/lib/active_support/executor.rb +8 -0
  190. data/lib/active_support/file_update_checker.rb +166 -0
  191. data/lib/active_support/fork_tracker.rb +43 -0
  192. data/lib/active_support/gem_version.rb +17 -0
  193. data/lib/active_support/gzip.rb +41 -0
  194. data/lib/active_support/hash_with_indifferent_access.rb +464 -0
  195. data/lib/active_support/html_safe_translation.rb +56 -0
  196. data/lib/active_support/i18n.rb +17 -0
  197. data/lib/active_support/i18n_railtie.rb +140 -0
  198. data/lib/active_support/inflections.rb +68 -49
  199. data/lib/active_support/inflector/inflections.rb +290 -0
  200. data/lib/active_support/inflector/methods.rb +387 -0
  201. data/lib/active_support/inflector/transliterate.rb +147 -0
  202. data/lib/active_support/inflector.rb +7 -164
  203. data/lib/active_support/isolated_execution_state.rb +76 -0
  204. data/lib/active_support/json/decoding.rb +78 -0
  205. data/lib/active_support/json/encoding.rb +256 -0
  206. data/lib/active_support/json.rb +4 -0
  207. data/lib/active_support/key_generator.rb +66 -0
  208. data/lib/active_support/lazy_load_hooks.rb +107 -0
  209. data/lib/active_support/locale/en.rb +33 -0
  210. data/lib/active_support/locale/en.yml +141 -0
  211. data/lib/active_support/log_subscriber/test_helper.rb +106 -0
  212. data/lib/active_support/log_subscriber.rb +188 -0
  213. data/lib/active_support/logger.rb +55 -0
  214. data/lib/active_support/logger_silence.rb +21 -0
  215. data/lib/active_support/logger_thread_safe_level.rb +50 -0
  216. data/lib/active_support/message_encryptor.rb +374 -0
  217. data/lib/active_support/message_encryptors.rb +193 -0
  218. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  219. data/lib/active_support/message_pack/extensions.rb +310 -0
  220. data/lib/active_support/message_pack/serializer.rb +63 -0
  221. data/lib/active_support/message_pack.rb +50 -0
  222. data/lib/active_support/message_verifier.rb +377 -0
  223. data/lib/active_support/message_verifiers.rb +189 -0
  224. data/lib/active_support/messages/codec.rb +65 -0
  225. data/lib/active_support/messages/metadata.rb +146 -0
  226. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  227. data/lib/active_support/messages/rotation_coordinator.rb +102 -0
  228. data/lib/active_support/messages/rotator.rb +69 -0
  229. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  230. data/lib/active_support/multibyte/chars.rb +188 -0
  231. data/lib/active_support/multibyte/unicode.rb +42 -0
  232. data/lib/active_support/multibyte.rb +27 -0
  233. data/lib/active_support/notifications/fanout.rb +467 -0
  234. data/lib/active_support/notifications/instrumenter.rb +240 -0
  235. data/lib/active_support/notifications.rb +281 -0
  236. data/lib/active_support/number_helper/number_converter.rb +190 -0
  237. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  238. data/lib/active_support/number_helper/number_to_delimited_converter.rb +30 -0
  239. data/lib/active_support/number_helper/number_to_human_converter.rb +69 -0
  240. data/lib/active_support/number_helper/number_to_human_size_converter.rb +60 -0
  241. data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
  242. data/lib/active_support/number_helper/number_to_phone_converter.rb +60 -0
  243. data/lib/active_support/number_helper/number_to_rounded_converter.rb +59 -0
  244. data/lib/active_support/number_helper/rounding_helper.rb +46 -0
  245. data/lib/active_support/number_helper.rb +479 -0
  246. data/lib/active_support/option_merger.rb +38 -0
  247. data/lib/active_support/ordered_hash.rb +50 -0
  248. data/lib/active_support/ordered_options.rb +141 -25
  249. data/lib/active_support/parameter_filter.rb +157 -0
  250. data/lib/active_support/rails.rb +26 -0
  251. data/lib/active_support/railtie.rb +180 -0
  252. data/lib/active_support/reloader.rb +138 -0
  253. data/lib/active_support/rescuable.rb +176 -0
  254. data/lib/active_support/secure_compare_rotator.rb +58 -0
  255. data/lib/active_support/security_utils.rb +38 -0
  256. data/lib/active_support/string_inquirer.rb +35 -0
  257. data/lib/active_support/structured_event_subscriber.rb +99 -0
  258. data/lib/active_support/subscriber.rb +141 -0
  259. data/lib/active_support/syntax_error_proxy.rb +67 -0
  260. data/lib/active_support/tagged_logging.rb +157 -0
  261. data/lib/active_support/test_case.rb +365 -0
  262. data/lib/active_support/testing/assertions.rb +369 -0
  263. data/lib/active_support/testing/autorun.rb +10 -0
  264. data/lib/active_support/testing/constant_lookup.rb +51 -0
  265. data/lib/active_support/testing/constant_stubbing.rb +54 -0
  266. data/lib/active_support/testing/declarative.rb +28 -0
  267. data/lib/active_support/testing/deprecation.rb +82 -0
  268. data/lib/active_support/testing/error_reporter_assertions.rb +124 -0
  269. data/lib/active_support/testing/event_reporter_assertions.rb +227 -0
  270. data/lib/active_support/testing/file_fixtures.rb +38 -0
  271. data/lib/active_support/testing/isolation.rb +121 -0
  272. data/lib/active_support/testing/method_call_assertions.rb +69 -0
  273. data/lib/active_support/testing/notification_assertions.rb +92 -0
  274. data/lib/active_support/testing/parallelization/server.rb +98 -0
  275. data/lib/active_support/testing/parallelization/worker.rb +107 -0
  276. data/lib/active_support/testing/parallelization.rb +79 -0
  277. data/lib/active_support/testing/parallelize_executor.rb +81 -0
  278. data/lib/active_support/testing/setup_and_teardown.rb +57 -0
  279. data/lib/active_support/testing/stream.rb +41 -0
  280. data/lib/active_support/testing/tagged_logging.rb +27 -0
  281. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  282. data/lib/active_support/testing/time_helpers.rb +273 -0
  283. data/lib/active_support/time.rb +20 -0
  284. data/lib/active_support/time_with_zone.rb +613 -0
  285. data/lib/active_support/values/time_zone.rb +599 -158
  286. data/lib/active_support/version.rb +7 -6
  287. data/lib/active_support/xml_mini/jdom.rb +175 -0
  288. data/lib/active_support/xml_mini/libxml.rb +80 -0
  289. data/lib/active_support/xml_mini/libxmlsax.rb +83 -0
  290. data/lib/active_support/xml_mini/nokogiri.rb +83 -0
  291. data/lib/active_support/xml_mini/nokogirisax.rb +86 -0
  292. data/lib/active_support/xml_mini/rexml.rb +137 -0
  293. data/lib/active_support/xml_mini.rb +212 -0
  294. data/lib/active_support.rb +122 -10
  295. metadata +524 -93
  296. data/CHANGELOG +0 -283
  297. data/lib/active_support/binding_of_caller.rb +0 -84
  298. data/lib/active_support/breakpoint.rb +0 -523
  299. data/lib/active_support/class_attribute_accessors.rb +0 -57
  300. data/lib/active_support/class_inheritable_attributes.rb +0 -117
  301. data/lib/active_support/clean_logger.rb +0 -36
  302. data/lib/active_support/core_ext/blank.rb +0 -38
  303. data/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +0 -14
  304. data/lib/active_support/core_ext/cgi.rb +0 -5
  305. data/lib/active_support/core_ext/exception.rb +0 -29
  306. data/lib/active_support/core_ext/integer/even_odd.rb +0 -24
  307. data/lib/active_support/core_ext/object_and_class.rb +0 -44
  308. data/lib/active_support/module_attribute_accessors.rb +0 -57
  309. data/lib/active_support/whiny_nil.rb +0 -38
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+
5
+ class File
6
+ # Write to a file atomically. Useful for situations where you don't
7
+ # want other processes or threads to see half-written files.
8
+ #
9
+ # File.atomic_write('important.file') do |file|
10
+ # file.write('hello')
11
+ # end
12
+ #
13
+ # This method needs to create a temporary file. By default it will create it
14
+ # in the same directory as the destination file. If you don't like this
15
+ # behavior you can provide a different directory but it must be on the
16
+ # same physical filesystem as the file you're trying to write.
17
+ #
18
+ # File.atomic_write('/data/something.important', '/data/tmp') do |file|
19
+ # file.write('hello')
20
+ # end
21
+ def self.atomic_write(file_name, temp_dir = dirname(file_name))
22
+ require "tempfile" unless defined?(Tempfile)
23
+
24
+ Tempfile.open(".#{basename(file_name)}", temp_dir) do |temp_file|
25
+ temp_file.binmode
26
+ return_val = yield temp_file
27
+ temp_file.close
28
+
29
+ old_stat = if exist?(file_name)
30
+ # Get original file permissions
31
+ stat(file_name)
32
+ else
33
+ # If not possible, probe which are the default permissions in the
34
+ # destination directory.
35
+ probe_stat_in(dirname(file_name))
36
+ end
37
+
38
+ if old_stat
39
+ # Set correct permissions on new file
40
+ begin
41
+ chown(old_stat.uid, old_stat.gid, temp_file.path)
42
+ # This operation will affect filesystem ACL's
43
+ chmod(old_stat.mode, temp_file.path)
44
+ rescue Errno::EPERM, Errno::EACCES
45
+ # Changing file ownership failed, moving on.
46
+ end
47
+ end
48
+
49
+ # Overwrite original file with temp file
50
+ rename(temp_file.path, file_name)
51
+ return_val
52
+ end
53
+ end
54
+
55
+ # Private utility method.
56
+ def self.probe_stat_in(dir) # :nodoc:
57
+ basename = [
58
+ ".permissions_check",
59
+ Thread.current.object_id,
60
+ Process.pid,
61
+ rand(1000000)
62
+ ].join(".")
63
+
64
+ file_name = join(dir, basename)
65
+ FileUtils.touch(file_name)
66
+ stat(file_name)
67
+ rescue Errno::ENOENT
68
+ file_name = nil
69
+ ensure
70
+ FileUtils.rm_f(file_name) if file_name
71
+ end
72
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "file/atomic"
@@ -0,0 +1,262 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/object/blank"
4
+ require "active_support/core_ext/object/to_param"
5
+ require "active_support/core_ext/object/to_query"
6
+ require "active_support/core_ext/object/try"
7
+ require "active_support/core_ext/array/wrap"
8
+ require "active_support/core_ext/hash/reverse_merge"
9
+ require "active_support/core_ext/string/inflections"
10
+
11
+ class Hash
12
+ # Returns a string containing an XML representation of its receiver:
13
+ #
14
+ # { foo: 1, bar: 2 }.to_xml
15
+ # # =>
16
+ # # <?xml version="1.0" encoding="UTF-8"?>
17
+ # # <hash>
18
+ # # <foo type="integer">1</foo>
19
+ # # <bar type="integer">2</bar>
20
+ # # </hash>
21
+ #
22
+ # To do so, the method loops over the pairs and builds nodes that depend on
23
+ # the _values_. Given a pair +key+, +value+:
24
+ #
25
+ # * If +value+ is a hash there's a recursive call with +key+ as <tt>:root</tt>.
26
+ #
27
+ # * If +value+ is an array there's a recursive call with +key+ as <tt>:root</tt>,
28
+ # and +key+ singularized as <tt>:children</tt>.
29
+ #
30
+ # * If +value+ is a callable object it must expect one or two arguments. Depending
31
+ # on the arity, the callable is invoked with the +options+ hash as first argument
32
+ # with +key+ as <tt>:root</tt>, and +key+ singularized as second argument. The
33
+ # callable can add nodes by using <tt>options[:builder]</tt>.
34
+ #
35
+ # {foo: lambda { |options, key| options[:builder].b(key) }}.to_xml
36
+ # # => "<b>foo</b>"
37
+ #
38
+ # * If +value+ responds to +to_xml+ the method is invoked with +key+ as <tt>:root</tt>.
39
+ #
40
+ # class Foo
41
+ # def to_xml(options)
42
+ # options[:builder].bar 'fooing!'
43
+ # end
44
+ # end
45
+ #
46
+ # { foo: Foo.new }.to_xml(skip_instruct: true)
47
+ # # =>
48
+ # # <hash>
49
+ # # <bar>fooing!</bar>
50
+ # # </hash>
51
+ #
52
+ # * Otherwise, a node with +key+ as tag is created with a string representation of
53
+ # +value+ as text node. If +value+ is +nil+ an attribute "nil" set to "true" is added.
54
+ # Unless the option <tt>:skip_types</tt> exists and is true, an attribute "type" is
55
+ # added as well according to the following mapping:
56
+ #
57
+ # XML_TYPE_NAMES = {
58
+ # "Symbol" => "symbol",
59
+ # "Integer" => "integer",
60
+ # "BigDecimal" => "decimal",
61
+ # "Float" => "float",
62
+ # "TrueClass" => "boolean",
63
+ # "FalseClass" => "boolean",
64
+ # "Date" => "date",
65
+ # "DateTime" => "dateTime",
66
+ # "Time" => "dateTime"
67
+ # }
68
+ #
69
+ # By default the root node is "hash", but that's configurable via the <tt>:root</tt> option.
70
+ #
71
+ # The default XML builder is a fresh instance of +Builder::XmlMarkup+. You can
72
+ # configure your own builder with the <tt>:builder</tt> option. The method also accepts
73
+ # options like <tt>:dasherize</tt> and friends, they are forwarded to the builder.
74
+ def to_xml(options = {})
75
+ require "active_support/builder" unless defined?(Builder::XmlMarkup)
76
+
77
+ options = options.dup
78
+ options[:indent] ||= 2
79
+ options[:root] ||= "hash"
80
+ options[:builder] ||= Builder::XmlMarkup.new(indent: options[:indent])
81
+
82
+ builder = options[:builder]
83
+ builder.instruct! unless options.delete(:skip_instruct)
84
+
85
+ root = ActiveSupport::XmlMini.rename_key(options[:root].to_s, options)
86
+
87
+ builder.tag!(root) do
88
+ each { |key, value| ActiveSupport::XmlMini.to_tag(key, value, options) }
89
+ yield builder if block_given?
90
+ end
91
+ end
92
+
93
+ class << self
94
+ # Returns a Hash containing a collection of pairs when the key is the node name and the value is
95
+ # its content
96
+ #
97
+ # xml = <<-XML
98
+ # <?xml version="1.0" encoding="UTF-8"?>
99
+ # <hash>
100
+ # <foo type="integer">1</foo>
101
+ # <bar type="integer">2</bar>
102
+ # </hash>
103
+ # XML
104
+ #
105
+ # hash = Hash.from_xml(xml)
106
+ # # => {"hash"=>{"foo"=>1, "bar"=>2}}
107
+ #
108
+ # +DisallowedType+ is raised if the XML contains attributes with <tt>type="yaml"</tt> or
109
+ # <tt>type="symbol"</tt>. Use <tt>Hash.from_trusted_xml</tt> to
110
+ # parse this XML.
111
+ #
112
+ # Custom +disallowed_types+ can also be passed in the form of an
113
+ # array.
114
+ #
115
+ # xml = <<-XML
116
+ # <?xml version="1.0" encoding="UTF-8"?>
117
+ # <hash>
118
+ # <foo type="integer">1</foo>
119
+ # <bar type="string">"David"</bar>
120
+ # </hash>
121
+ # XML
122
+ #
123
+ # hash = Hash.from_xml(xml, ['integer'])
124
+ # # => ActiveSupport::XMLConverter::DisallowedType: Disallowed type attribute: "integer"
125
+ #
126
+ # Note that passing custom disallowed types will override the default types,
127
+ # which are Symbol and YAML.
128
+ def from_xml(xml, disallowed_types = nil)
129
+ ActiveSupport::XMLConverter.new(xml, disallowed_types).to_h
130
+ end
131
+
132
+ # Builds a Hash from XML just like <tt>Hash.from_xml</tt>, but also allows Symbol and YAML.
133
+ def from_trusted_xml(xml)
134
+ from_xml xml, []
135
+ end
136
+ end
137
+ end
138
+
139
+ module ActiveSupport
140
+ class XMLConverter # :nodoc:
141
+ # Raised if the XML contains attributes with type="yaml" or
142
+ # type="symbol". Read Hash#from_xml for more details.
143
+ class DisallowedType < StandardError
144
+ def initialize(type)
145
+ super "Disallowed type attribute: #{type.inspect}"
146
+ end
147
+ end
148
+
149
+ DISALLOWED_TYPES = %w(symbol yaml)
150
+
151
+ def initialize(xml, disallowed_types = nil)
152
+ @xml = normalize_keys(XmlMini.parse(xml))
153
+ @disallowed_types = disallowed_types || DISALLOWED_TYPES
154
+ end
155
+
156
+ def to_h
157
+ deep_to_h(@xml)
158
+ end
159
+
160
+ private
161
+ def normalize_keys(params)
162
+ case params
163
+ when Hash
164
+ Hash[params.map { |k, v| [k.to_s.tr("-", "_"), normalize_keys(v)] } ]
165
+ when Array
166
+ params.map { |v| normalize_keys(v) }
167
+ else
168
+ params
169
+ end
170
+ end
171
+
172
+ def deep_to_h(value)
173
+ case value
174
+ when Hash
175
+ process_hash(value)
176
+ when Array
177
+ process_array(value)
178
+ when String
179
+ value
180
+ else
181
+ raise "can't typecast #{value.class.name} - #{value.inspect}"
182
+ end
183
+ end
184
+
185
+ def process_hash(value)
186
+ if value.include?("type") && !value["type"].is_a?(Hash) && @disallowed_types.include?(value["type"])
187
+ raise DisallowedType, value["type"]
188
+ end
189
+
190
+ if become_array?(value)
191
+ _, entries = Array.wrap(value.detect { |k, v| not v.is_a?(String) })
192
+ if entries.nil? || value["__content__"].try(:empty?)
193
+ []
194
+ else
195
+ case entries
196
+ when Array
197
+ entries.collect { |v| deep_to_h(v) }
198
+ when Hash
199
+ [deep_to_h(entries)]
200
+ else
201
+ raise "can't typecast #{entries.inspect}"
202
+ end
203
+ end
204
+ elsif become_content?(value)
205
+ process_content(value)
206
+
207
+ elsif become_empty_string?(value)
208
+ ""
209
+ elsif become_hash?(value)
210
+ xml_value = value.transform_values { |v| deep_to_h(v) }
211
+
212
+ # Turn { files: { file: #<StringIO> } } into { files: #<StringIO> } so it is compatible with
213
+ # how multipart uploaded files from HTML appear
214
+ xml_value["file"].is_a?(StringIO) ? xml_value["file"] : xml_value
215
+ end
216
+ end
217
+
218
+ def become_content?(value)
219
+ value["type"] == "file" || (value["__content__"] && (value.keys.size == 1 || value["__content__"].present?))
220
+ end
221
+
222
+ def become_array?(value)
223
+ value["type"] == "array"
224
+ end
225
+
226
+ def become_empty_string?(value)
227
+ # { "string" => true }
228
+ # No tests fail when the second term is removed.
229
+ value["type"] == "string" && value["nil"] != "true"
230
+ end
231
+
232
+ def become_hash?(value)
233
+ !nothing?(value) && !garbage?(value)
234
+ end
235
+
236
+ def nothing?(value)
237
+ # blank or nil parsed values are represented by nil
238
+ value.blank? || value["nil"] == "true"
239
+ end
240
+
241
+ def garbage?(value)
242
+ # If the type is the only element which makes it then
243
+ # this still makes the value nil, except if type is
244
+ # an XML node(where type['value'] is a Hash)
245
+ value["type"] && !value["type"].is_a?(::Hash) && value.size == 1
246
+ end
247
+
248
+ def process_content(value)
249
+ content = value["__content__"]
250
+ if parser = ActiveSupport::XmlMini::PARSING[value["type"]]
251
+ parser.arity == 1 ? parser.call(content) : parser.call(content, value)
252
+ else
253
+ content
254
+ end
255
+ end
256
+
257
+ def process_array(value)
258
+ value.map! { |i| deep_to_h(i) }
259
+ value.length > 1 ? value : value.first
260
+ end
261
+ end
262
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/deep_mergeable"
4
+
5
+ class Hash
6
+ include ActiveSupport::DeepMergeable
7
+
8
+ ##
9
+ # :method: deep_merge
10
+ # :call-seq: deep_merge(other_hash, &block)
11
+ #
12
+ # Returns a new hash with +self+ and +other_hash+ merged recursively.
13
+ #
14
+ # h1 = { a: true, b: { c: [1, 2, 3] } }
15
+ # h2 = { a: false, b: { x: [3, 4, 5] } }
16
+ #
17
+ # h1.deep_merge(h2) # => { a: false, b: { c: [1, 2, 3], x: [3, 4, 5] } }
18
+ #
19
+ # Like with Hash#merge in the standard library, a block can be provided
20
+ # to merge values:
21
+ #
22
+ # h1 = { a: 100, b: 200, c: { c1: 100 } }
23
+ # h2 = { b: 250, c: { c1: 200 } }
24
+ # h1.deep_merge(h2) { |key, this_val, other_val| this_val + other_val }
25
+ # # => { a: 100, b: 450, c: { c1: 300 } }
26
+ #
27
+ #--
28
+ # Implemented by ActiveSupport::DeepMergeable#deep_merge.
29
+
30
+ ##
31
+ # :method: deep_merge!
32
+ # :call-seq: deep_merge!(other_hash, &block)
33
+ #
34
+ # Same as #deep_merge, but modifies +self+.
35
+ #
36
+ #--
37
+ # Implemented by ActiveSupport::DeepMergeable#deep_merge!.
38
+
39
+ ##
40
+ def deep_merge?(other) # :nodoc:
41
+ other.is_a?(Hash)
42
+ end
43
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Hash
4
+ # Returns a new hash with all values converted by the block operation.
5
+ # This includes the values from the root hash and from all
6
+ # nested hashes and arrays.
7
+ #
8
+ # hash = { person: { name: 'Rob', age: '28' } }
9
+ #
10
+ # hash.deep_transform_values{ |value| value.to_s.upcase }
11
+ # # => {person: {name: "ROB", age: "28"}}
12
+ def deep_transform_values(&block)
13
+ _deep_transform_values_in_object(self, &block)
14
+ end
15
+
16
+ # Destructively converts all values by using the block operation.
17
+ # This includes the values from the root hash and from all
18
+ # nested hashes and arrays.
19
+ def deep_transform_values!(&block)
20
+ _deep_transform_values_in_object!(self, &block)
21
+ end
22
+
23
+ private
24
+ # Support methods for deep transforming nested hashes and arrays.
25
+ def _deep_transform_values_in_object(object, &block)
26
+ case object
27
+ when Hash
28
+ object.transform_values { |value| _deep_transform_values_in_object(value, &block) }
29
+ when Array
30
+ object.map { |e| _deep_transform_values_in_object(e, &block) }
31
+ else
32
+ yield(object)
33
+ end
34
+ end
35
+
36
+ def _deep_transform_values_in_object!(object, &block)
37
+ case object
38
+ when Hash
39
+ object.transform_values! { |value| _deep_transform_values_in_object!(value, &block) }
40
+ when Array
41
+ object.map! { |e| _deep_transform_values_in_object!(e, &block) }
42
+ else
43
+ yield(object)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Hash
4
+ # Removes the given keys from hash and returns it.
5
+ # hash = { a: true, b: false, c: nil }
6
+ # hash.except!(:c) # => { a: true, b: false }
7
+ # hash # => { a: true, b: false }
8
+ def except!(*keys)
9
+ keys.each { |key| delete(key) }
10
+ self
11
+ end
12
+ end
@@ -1,60 +1,24 @@
1
- # This implementation is HODEL-HASH-9600 compliant
2
- class HashWithIndifferentAccess < Hash
3
- def initialize(constructor = {})
4
- if constructor.is_a?(Hash)
5
- super()
6
- update(constructor)
7
- else
8
- super(constructor)
9
- end
10
- end
11
-
12
- def default(key)
13
- self[key.to_s] if key.is_a?(Symbol)
14
- end
15
-
16
- alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
17
-
18
- def []=(key, value)
19
- regular_writer(convert_key(key), convert_value(value))
20
- end
21
- def update(hash)
22
- hash.each {|key, value| self[key] = value}
23
- end
24
-
25
- def key?(key)
26
- super(convert_key(key))
27
- end
1
+ # frozen_string_literal: true
28
2
 
29
- alias_method :include?, :key?
30
- alias_method :has_key?, :key?
31
- alias_method :member?, :key?
3
+ require "active_support/hash_with_indifferent_access"
32
4
 
33
- def fetch(key, *extras)
34
- super(convert_key(key), *extras)
5
+ class Hash
6
+ # Returns an ActiveSupport::HashWithIndifferentAccess out of its receiver:
7
+ #
8
+ # { a: 1 }.with_indifferent_access['a'] # => 1
9
+ def with_indifferent_access
10
+ ActiveSupport::HashWithIndifferentAccess.new(self)
35
11
  end
36
12
 
37
- def values_at(*indices)
38
- indices.collect {|key| self[convert_key(key)]}
39
- end
40
-
41
- protected
42
- def convert_key(key)
43
- key.kind_of?(Symbol) ? key.to_s : key
44
- end
45
- def convert_value(value)
46
- value.is_a?(Hash) ? value.with_indifferent_access : value
47
- end
48
- end
49
-
50
- module ActiveSupport #:nodoc:
51
- module CoreExtensions #:nodoc:
52
- module Hash #:nodoc:
53
- module IndifferentAccess #:nodoc:
54
- def with_indifferent_access
55
- HashWithIndifferentAccess.new(self)
56
- end
57
- end
58
- end
59
- end
13
+ # Called when object is nested under an object that receives
14
+ # #with_indifferent_access. This method will be called on the current object
15
+ # by the enclosing object and is aliased to #with_indifferent_access by
16
+ # default. Subclasses of Hash may override this method to return +self+ if
17
+ # converting to an ActiveSupport::HashWithIndifferentAccess would not be
18
+ # desirable.
19
+ #
20
+ # b = { b: 1 }
21
+ # { a: b }.with_indifferent_access['a'] # calls b.nested_under_indifferent_access
22
+ # # => {"b"=>1}
23
+ alias nested_under_indifferent_access with_indifferent_access
60
24
  end