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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +505 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +40 -0
- data/lib/active_support/actionable_error.rb +50 -0
- data/lib/active_support/all.rb +5 -0
- data/lib/active_support/array_inquirer.rb +50 -0
- data/lib/active_support/backtrace_cleaner.rb +234 -0
- data/lib/active_support/benchmark.rb +21 -0
- data/lib/active_support/benchmarkable.rb +53 -0
- data/lib/active_support/broadcast_logger.rb +238 -0
- data/lib/active_support/builder.rb +8 -0
- data/lib/active_support/cache/coder.rb +153 -0
- data/lib/active_support/cache/entry.rb +134 -0
- data/lib/active_support/cache/file_store.rb +244 -0
- data/lib/active_support/cache/mem_cache_store.rb +288 -0
- data/lib/active_support/cache/memory_store.rb +264 -0
- data/lib/active_support/cache/null_store.rb +62 -0
- data/lib/active_support/cache/redis_cache_store.rb +498 -0
- data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
- data/lib/active_support/cache/strategy/local_cache.rb +246 -0
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
- data/lib/active_support/cache.rb +1170 -0
- data/lib/active_support/callbacks.rb +960 -0
- data/lib/active_support/class_attribute.rb +33 -0
- data/lib/active_support/code_generator.rb +79 -0
- data/lib/active_support/concern.rb +217 -0
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
- data/lib/active_support/concurrency/null_lock.rb +13 -0
- data/lib/active_support/concurrency/share_lock.rb +225 -0
- data/lib/active_support/concurrency/thread_monitor.rb +55 -0
- data/lib/active_support/configurable.rb +193 -0
- data/lib/active_support/configuration_file.rb +60 -0
- data/lib/active_support/continuous_integration.rb +145 -0
- data/lib/active_support/core_ext/array/access.rb +100 -0
- data/lib/active_support/core_ext/array/conversions.rb +209 -26
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array/extract_options.rb +31 -0
- data/lib/active_support/core_ext/array/grouping.rb +109 -0
- data/lib/active_support/core_ext/array/inquiry.rb +19 -0
- data/lib/active_support/core_ext/array/wrap.rb +48 -0
- data/lib/active_support/core_ext/array.rb +8 -4
- data/lib/active_support/core_ext/benchmark.rb +6 -0
- data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
- data/lib/active_support/core_ext/big_decimal.rb +3 -0
- data/lib/active_support/core_ext/class/attribute.rb +137 -0
- data/lib/active_support/core_ext/class/attribute_accessors.rb +6 -0
- data/lib/active_support/core_ext/class/subclasses.rb +24 -0
- data/lib/active_support/core_ext/class.rb +4 -0
- data/lib/active_support/core_ext/date/acts_like.rb +10 -0
- data/lib/active_support/core_ext/date/blank.rb +18 -0
- data/lib/active_support/core_ext/date/calculations.rb +161 -0
- data/lib/active_support/core_ext/date/conversions.rb +95 -28
- data/lib/active_support/core_ext/date/zones.rb +8 -0
- data/lib/active_support/core_ext/date.rb +6 -5
- data/lib/active_support/core_ext/date_and_time/calculations.rb +374 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +23 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
- data/lib/active_support/core_ext/date_time/acts_like.rb +16 -0
- data/lib/active_support/core_ext/date_time/blank.rb +18 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +215 -0
- data/lib/active_support/core_ext/date_time/compatibility.rb +16 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +108 -0
- data/lib/active_support/core_ext/date_time.rb +7 -0
- data/lib/active_support/core_ext/digest/uuid.rb +76 -0
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +277 -7
- data/lib/active_support/core_ext/erb/util.rb +201 -0
- data/lib/active_support/core_ext/file/atomic.rb +72 -0
- data/lib/active_support/core_ext/file.rb +3 -0
- data/lib/active_support/core_ext/hash/conversions.rb +262 -0
- data/lib/active_support/core_ext/hash/deep_merge.rb +43 -0
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +12 -0
- data/lib/active_support/core_ext/hash/indifferent_access.rb +19 -55
- data/lib/active_support/core_ext/hash/keys.rb +134 -44
- data/lib/active_support/core_ext/hash/reverse_merge.rb +22 -22
- data/lib/active_support/core_ext/hash/slice.rb +27 -0
- data/lib/active_support/core_ext/hash.rb +9 -8
- data/lib/active_support/core_ext/integer/inflections.rb +29 -13
- data/lib/active_support/core_ext/integer/multiple.rb +12 -0
- data/lib/active_support/core_ext/integer/time.rb +22 -0
- data/lib/active_support/core_ext/integer.rb +4 -6
- data/lib/active_support/core_ext/kernel/concern.rb +14 -0
- data/lib/active_support/core_ext/kernel/reporting.rb +45 -0
- data/lib/active_support/core_ext/kernel/singleton_class.rb +8 -0
- data/lib/active_support/core_ext/kernel.rb +4 -78
- data/lib/active_support/core_ext/load_error.rb +6 -35
- data/lib/active_support/core_ext/module/aliasing.rb +31 -0
- data/lib/active_support/core_ext/module/anonymous.rb +30 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +48 -0
- data/lib/active_support/core_ext/module/attribute_accessors.rb +214 -0
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +175 -0
- data/lib/active_support/core_ext/module/concerning.rb +140 -0
- data/lib/active_support/core_ext/module/delegation.rb +225 -0
- data/lib/active_support/core_ext/module/deprecation.rb +25 -0
- data/lib/active_support/core_ext/module/introspection.rb +65 -0
- data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
- data/lib/active_support/core_ext/module/remove_method.rb +17 -0
- data/lib/active_support/core_ext/module.rb +13 -0
- data/lib/active_support/core_ext/name_error.rb +59 -0
- data/lib/active_support/core_ext/numeric/bytes.rb +73 -42
- data/lib/active_support/core_ext/numeric/conversions.rb +145 -0
- data/lib/active_support/core_ext/numeric/time.rb +64 -57
- data/lib/active_support/core_ext/numeric.rb +4 -6
- data/lib/active_support/core_ext/object/acts_like.rb +45 -0
- data/lib/active_support/core_ext/object/blank.rb +199 -0
- data/lib/active_support/core_ext/object/conversions.rb +6 -0
- data/lib/active_support/core_ext/object/deep_dup.rb +71 -0
- data/lib/active_support/core_ext/object/duplicable.rb +69 -0
- data/lib/active_support/core_ext/object/inclusion.rb +37 -0
- data/lib/active_support/core_ext/object/instance_variables.rb +32 -0
- data/lib/active_support/core_ext/object/json.rb +267 -0
- data/lib/active_support/core_ext/object/to_param.rb +3 -0
- data/lib/active_support/core_ext/object/to_query.rb +93 -0
- data/lib/active_support/core_ext/object/try.rb +158 -0
- data/lib/active_support/core_ext/object/with.rb +46 -0
- data/lib/active_support/core_ext/object/with_options.rb +101 -0
- data/lib/active_support/core_ext/object.rb +17 -0
- data/lib/active_support/core_ext/pathname/blank.rb +20 -0
- data/lib/active_support/core_ext/pathname/existence.rb +23 -0
- data/lib/active_support/core_ext/pathname.rb +4 -0
- data/lib/active_support/core_ext/range/compare_range.rb +57 -0
- data/lib/active_support/core_ext/range/conversions.rb +58 -17
- data/lib/active_support/core_ext/range/overlap.rb +40 -0
- data/lib/active_support/core_ext/range/sole.rb +17 -0
- data/lib/active_support/core_ext/range.rb +5 -4
- data/lib/active_support/core_ext/regexp.rb +14 -0
- data/lib/active_support/core_ext/securerandom.rb +57 -0
- data/lib/active_support/core_ext/string/access.rb +93 -56
- data/lib/active_support/core_ext/string/behavior.rb +8 -0
- data/lib/active_support/core_ext/string/conversions.rb +57 -16
- data/lib/active_support/core_ext/string/exclude.rb +13 -0
- data/lib/active_support/core_ext/string/filters.rb +151 -0
- data/lib/active_support/core_ext/string/indent.rb +45 -0
- data/lib/active_support/core_ext/string/inflections.rb +297 -54
- data/lib/active_support/core_ext/string/inquiry.rb +16 -0
- data/lib/active_support/core_ext/string/multibyte.rb +67 -0
- data/lib/active_support/core_ext/string/output_safety.rb +235 -0
- data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -18
- data/lib/active_support/core_ext/string/strip.rb +27 -0
- data/lib/active_support/core_ext/string/zones.rb +16 -0
- data/lib/active_support/core_ext/string.rb +14 -10
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/thread/backtrace/location.rb +7 -0
- data/lib/active_support/core_ext/time/acts_like.rb +10 -0
- data/lib/active_support/core_ext/time/calculations.rb +358 -153
- data/lib/active_support/core_ext/time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/time/conversions.rb +69 -30
- data/lib/active_support/core_ext/time/zones.rb +97 -0
- data/lib/active_support/core_ext/time.rb +6 -6
- data/lib/active_support/core_ext.rb +5 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +243 -0
- data/lib/active_support/deep_mergeable.rb +53 -0
- data/lib/active_support/delegation.rb +183 -0
- data/lib/active_support/dependencies/autoload.rb +72 -0
- data/lib/active_support/dependencies/interlock.rb +55 -0
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +84 -222
- data/lib/active_support/deprecation/behaviors.rb +148 -0
- data/lib/active_support/deprecation/constant_accessor.rb +74 -0
- data/lib/active_support/deprecation/deprecators.rb +104 -0
- data/lib/active_support/deprecation/disallowed.rb +54 -0
- data/lib/active_support/deprecation/method_wrappers.rb +68 -0
- data/lib/active_support/deprecation/proxy_wrappers.rb +189 -0
- data/lib/active_support/deprecation/reporting.rb +162 -0
- data/lib/active_support/deprecation.rb +81 -0
- data/lib/active_support/deprecator.rb +7 -0
- data/lib/active_support/descendants_tracker.rb +112 -0
- data/lib/active_support/digest.rb +22 -0
- data/lib/active_support/duration/iso8601_parser.rb +123 -0
- data/lib/active_support/duration/iso8601_serializer.rb +64 -0
- data/lib/active_support/duration.rb +524 -0
- data/lib/active_support/editor.rb +70 -0
- data/lib/active_support/encrypted_configuration.rb +126 -0
- data/lib/active_support/encrypted_file.rb +133 -0
- data/lib/active_support/environment_inquirer.rb +40 -0
- data/lib/active_support/error_reporter/test_helper.rb +15 -0
- data/lib/active_support/error_reporter.rb +318 -0
- data/lib/active_support/event_reporter/test_helper.rb +32 -0
- data/lib/active_support/event_reporter.rb +592 -0
- data/lib/active_support/evented_file_update_checker.rb +185 -0
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +110 -0
- data/lib/active_support/execution_wrapper.rb +150 -0
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/executor.rb +8 -0
- data/lib/active_support/file_update_checker.rb +166 -0
- data/lib/active_support/fork_tracker.rb +43 -0
- data/lib/active_support/gem_version.rb +17 -0
- data/lib/active_support/gzip.rb +41 -0
- data/lib/active_support/hash_with_indifferent_access.rb +464 -0
- data/lib/active_support/html_safe_translation.rb +56 -0
- data/lib/active_support/i18n.rb +17 -0
- data/lib/active_support/i18n_railtie.rb +140 -0
- data/lib/active_support/inflections.rb +68 -49
- data/lib/active_support/inflector/inflections.rb +290 -0
- data/lib/active_support/inflector/methods.rb +387 -0
- data/lib/active_support/inflector/transliterate.rb +147 -0
- data/lib/active_support/inflector.rb +7 -164
- data/lib/active_support/isolated_execution_state.rb +76 -0
- data/lib/active_support/json/decoding.rb +78 -0
- data/lib/active_support/json/encoding.rb +256 -0
- data/lib/active_support/json.rb +4 -0
- data/lib/active_support/key_generator.rb +66 -0
- data/lib/active_support/lazy_load_hooks.rb +107 -0
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +141 -0
- data/lib/active_support/log_subscriber/test_helper.rb +106 -0
- data/lib/active_support/log_subscriber.rb +188 -0
- data/lib/active_support/logger.rb +55 -0
- data/lib/active_support/logger_silence.rb +21 -0
- data/lib/active_support/logger_thread_safe_level.rb +50 -0
- data/lib/active_support/message_encryptor.rb +374 -0
- data/lib/active_support/message_encryptors.rb +193 -0
- data/lib/active_support/message_pack/cache_serializer.rb +23 -0
- data/lib/active_support/message_pack/extensions.rb +310 -0
- data/lib/active_support/message_pack/serializer.rb +63 -0
- data/lib/active_support/message_pack.rb +50 -0
- data/lib/active_support/message_verifier.rb +377 -0
- data/lib/active_support/message_verifiers.rb +189 -0
- data/lib/active_support/messages/codec.rb +65 -0
- data/lib/active_support/messages/metadata.rb +146 -0
- data/lib/active_support/messages/rotation_configuration.rb +23 -0
- data/lib/active_support/messages/rotation_coordinator.rb +102 -0
- data/lib/active_support/messages/rotator.rb +69 -0
- data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
- data/lib/active_support/multibyte/chars.rb +188 -0
- data/lib/active_support/multibyte/unicode.rb +42 -0
- data/lib/active_support/multibyte.rb +27 -0
- data/lib/active_support/notifications/fanout.rb +467 -0
- data/lib/active_support/notifications/instrumenter.rb +240 -0
- data/lib/active_support/notifications.rb +281 -0
- data/lib/active_support/number_helper/number_converter.rb +190 -0
- data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +30 -0
- data/lib/active_support/number_helper/number_to_human_converter.rb +69 -0
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +60 -0
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
- data/lib/active_support/number_helper/number_to_phone_converter.rb +60 -0
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +59 -0
- data/lib/active_support/number_helper/rounding_helper.rb +46 -0
- data/lib/active_support/number_helper.rb +479 -0
- data/lib/active_support/option_merger.rb +38 -0
- data/lib/active_support/ordered_hash.rb +50 -0
- data/lib/active_support/ordered_options.rb +141 -25
- data/lib/active_support/parameter_filter.rb +157 -0
- data/lib/active_support/rails.rb +26 -0
- data/lib/active_support/railtie.rb +180 -0
- data/lib/active_support/reloader.rb +138 -0
- data/lib/active_support/rescuable.rb +176 -0
- data/lib/active_support/secure_compare_rotator.rb +58 -0
- data/lib/active_support/security_utils.rb +38 -0
- data/lib/active_support/string_inquirer.rb +35 -0
- data/lib/active_support/structured_event_subscriber.rb +99 -0
- data/lib/active_support/subscriber.rb +141 -0
- data/lib/active_support/syntax_error_proxy.rb +67 -0
- data/lib/active_support/tagged_logging.rb +157 -0
- data/lib/active_support/test_case.rb +365 -0
- data/lib/active_support/testing/assertions.rb +369 -0
- data/lib/active_support/testing/autorun.rb +10 -0
- data/lib/active_support/testing/constant_lookup.rb +51 -0
- data/lib/active_support/testing/constant_stubbing.rb +54 -0
- data/lib/active_support/testing/declarative.rb +28 -0
- data/lib/active_support/testing/deprecation.rb +82 -0
- data/lib/active_support/testing/error_reporter_assertions.rb +124 -0
- data/lib/active_support/testing/event_reporter_assertions.rb +227 -0
- data/lib/active_support/testing/file_fixtures.rb +38 -0
- data/lib/active_support/testing/isolation.rb +121 -0
- data/lib/active_support/testing/method_call_assertions.rb +69 -0
- data/lib/active_support/testing/notification_assertions.rb +92 -0
- data/lib/active_support/testing/parallelization/server.rb +98 -0
- data/lib/active_support/testing/parallelization/worker.rb +107 -0
- data/lib/active_support/testing/parallelization.rb +79 -0
- data/lib/active_support/testing/parallelize_executor.rb +81 -0
- data/lib/active_support/testing/setup_and_teardown.rb +57 -0
- data/lib/active_support/testing/stream.rb +41 -0
- data/lib/active_support/testing/tagged_logging.rb +27 -0
- data/lib/active_support/testing/tests_without_assertions.rb +19 -0
- data/lib/active_support/testing/time_helpers.rb +273 -0
- data/lib/active_support/time.rb +20 -0
- data/lib/active_support/time_with_zone.rb +613 -0
- data/lib/active_support/values/time_zone.rb +599 -158
- data/lib/active_support/version.rb +7 -6
- data/lib/active_support/xml_mini/jdom.rb +175 -0
- data/lib/active_support/xml_mini/libxml.rb +80 -0
- data/lib/active_support/xml_mini/libxmlsax.rb +83 -0
- data/lib/active_support/xml_mini/nokogiri.rb +83 -0
- data/lib/active_support/xml_mini/nokogirisax.rb +86 -0
- data/lib/active_support/xml_mini/rexml.rb +137 -0
- data/lib/active_support/xml_mini.rb +212 -0
- data/lib/active_support.rb +122 -10
- metadata +524 -93
- data/CHANGELOG +0 -283
- data/lib/active_support/binding_of_caller.rb +0 -84
- data/lib/active_support/breakpoint.rb +0 -523
- data/lib/active_support/class_attribute_accessors.rb +0 -57
- data/lib/active_support/class_inheritable_attributes.rb +0 -117
- data/lib/active_support/clean_logger.rb +0 -36
- data/lib/active_support/core_ext/blank.rb +0 -38
- data/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +0 -14
- data/lib/active_support/core_ext/cgi.rb +0 -5
- data/lib/active_support/core_ext/exception.rb +0 -29
- data/lib/active_support/core_ext/integer/even_odd.rb +0 -24
- data/lib/active_support/core_ext/object_and_class.rb +0 -44
- data/lib/active_support/module_attribute_accessors.rb +0 -57
- 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,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
|
-
#
|
|
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
|
-
|
|
30
|
-
alias_method :has_key?, :key?
|
|
31
|
-
alias_method :member?, :key?
|
|
3
|
+
require "active_support/hash_with_indifferent_access"
|
|
32
4
|
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|