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
|
@@ -1,29 +1,212 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/core_ext/hash/keys"
|
|
4
|
+
require "active_support/core_ext/string/inflections"
|
|
5
|
+
require "active_support/core_ext/object/to_param"
|
|
6
|
+
require "active_support/core_ext/object/to_query"
|
|
7
|
+
|
|
8
|
+
class Array
|
|
9
|
+
# Converts the array to a comma-separated sentence where the last element is
|
|
10
|
+
# joined by the connector word.
|
|
11
|
+
#
|
|
12
|
+
# You can pass the following options to change the default behavior. If you
|
|
13
|
+
# pass an option key that doesn't exist in the list below, it will raise an
|
|
14
|
+
# <tt>ArgumentError</tt>.
|
|
15
|
+
#
|
|
16
|
+
# ==== Options
|
|
17
|
+
#
|
|
18
|
+
# * <tt>:words_connector</tt> - The sign or word used to join all but the last
|
|
19
|
+
# element in arrays with three or more elements (default: <tt>", "</tt>).
|
|
20
|
+
# * <tt>:last_word_connector</tt> - The sign or word used to join the last element
|
|
21
|
+
# in arrays with three or more elements (default: <tt>", and "</tt>).
|
|
22
|
+
# * <tt>:two_words_connector</tt> - The sign or word used to join the elements
|
|
23
|
+
# in arrays with two elements (default: <tt>" and "</tt>).
|
|
24
|
+
# * <tt>:locale</tt> - If +i18n+ is available, you can set a locale and use
|
|
25
|
+
# the connector options defined on the 'support.array' namespace in the
|
|
26
|
+
# corresponding dictionary file.
|
|
27
|
+
#
|
|
28
|
+
# ==== Examples
|
|
29
|
+
#
|
|
30
|
+
# [].to_sentence # => ""
|
|
31
|
+
# ['one'].to_sentence # => "one"
|
|
32
|
+
# ['one', 'two'].to_sentence # => "one and two"
|
|
33
|
+
# ['one', 'two', 'three'].to_sentence # => "one, two, and three"
|
|
34
|
+
#
|
|
35
|
+
# ['one', 'two'].to_sentence(passing: 'invalid option')
|
|
36
|
+
# # => ArgumentError: Unknown key: :passing. Valid keys are: :words_connector, :two_words_connector, :last_word_connector, :locale
|
|
37
|
+
#
|
|
38
|
+
# ['one', 'two'].to_sentence(two_words_connector: '-')
|
|
39
|
+
# # => "one-two"
|
|
40
|
+
#
|
|
41
|
+
# ['one', 'two', 'three'].to_sentence(words_connector: ' or ', last_word_connector: ' or at least ')
|
|
42
|
+
# # => "one or two or at least three"
|
|
43
|
+
#
|
|
44
|
+
# Using <tt>:locale</tt> option:
|
|
45
|
+
#
|
|
46
|
+
# # Given this locale dictionary:
|
|
47
|
+
# #
|
|
48
|
+
# # es:
|
|
49
|
+
# # support:
|
|
50
|
+
# # array:
|
|
51
|
+
# # words_connector: " o "
|
|
52
|
+
# # two_words_connector: " y "
|
|
53
|
+
# # last_word_connector: " o al menos "
|
|
54
|
+
#
|
|
55
|
+
# ['uno', 'dos'].to_sentence(locale: :es)
|
|
56
|
+
# # => "uno y dos"
|
|
57
|
+
#
|
|
58
|
+
# ['uno', 'dos', 'tres'].to_sentence(locale: :es)
|
|
59
|
+
# # => "uno o dos o al menos tres"
|
|
60
|
+
def to_sentence(options = {})
|
|
61
|
+
options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale)
|
|
62
|
+
|
|
63
|
+
default_connectors = {
|
|
64
|
+
words_connector: ", ",
|
|
65
|
+
two_words_connector: " and ",
|
|
66
|
+
last_word_connector: ", and "
|
|
67
|
+
}
|
|
68
|
+
if options[:locale] != false && defined?(I18n)
|
|
69
|
+
i18n_connectors = I18n.translate(:'support.array', locale: options[:locale], default: {})
|
|
70
|
+
default_connectors.merge!(i18n_connectors)
|
|
71
|
+
end
|
|
72
|
+
options = default_connectors.merge!(options)
|
|
73
|
+
|
|
74
|
+
case length
|
|
75
|
+
when 0
|
|
76
|
+
+""
|
|
77
|
+
when 1
|
|
78
|
+
+"#{self[0]}"
|
|
79
|
+
when 2
|
|
80
|
+
+"#{self[0]}#{options[:two_words_connector]}#{self[1]}"
|
|
81
|
+
else
|
|
82
|
+
+"#{self[0...-1].join(options[:words_connector])}#{options[:last_word_connector]}#{self[-1]}"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Extends <tt>Array#to_s</tt> to convert a collection of elements into a
|
|
87
|
+
# comma separated id list if <tt>:db</tt> argument is given as the format.
|
|
88
|
+
#
|
|
89
|
+
# This method is aliased to <tt>to_formatted_s</tt>.
|
|
90
|
+
#
|
|
91
|
+
# Blog.all.to_fs(:db) # => "1,2,3"
|
|
92
|
+
# Blog.none.to_fs(:db) # => "null"
|
|
93
|
+
# [1,2].to_fs # => "[1, 2]"
|
|
94
|
+
def to_fs(format = :default)
|
|
95
|
+
case format
|
|
96
|
+
when :db
|
|
97
|
+
if empty?
|
|
98
|
+
"null"
|
|
99
|
+
else
|
|
100
|
+
collect(&:id).join(",")
|
|
101
|
+
end
|
|
102
|
+
else
|
|
103
|
+
to_s
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
alias_method :to_formatted_s, :to_fs
|
|
107
|
+
|
|
108
|
+
# Returns a string that represents the array in XML by invoking +to_xml+
|
|
109
|
+
# on each element. Active Record collections delegate their representation
|
|
110
|
+
# in XML to this method.
|
|
111
|
+
#
|
|
112
|
+
# All elements are expected to respond to +to_xml+, if any of them does
|
|
113
|
+
# not then an exception is raised.
|
|
114
|
+
#
|
|
115
|
+
# The root node reflects the class name of the first element in plural
|
|
116
|
+
# if all elements belong to the same type and that's not Hash:
|
|
117
|
+
#
|
|
118
|
+
# customer.projects.to_xml
|
|
119
|
+
#
|
|
120
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
|
121
|
+
# <projects type="array">
|
|
122
|
+
# <project>
|
|
123
|
+
# <amount type="decimal">20000.0</amount>
|
|
124
|
+
# <customer-id type="integer">1567</customer-id>
|
|
125
|
+
# <deal-date type="date">2008-04-09</deal-date>
|
|
126
|
+
# ...
|
|
127
|
+
# </project>
|
|
128
|
+
# <project>
|
|
129
|
+
# <amount type="decimal">57230.0</amount>
|
|
130
|
+
# <customer-id type="integer">1567</customer-id>
|
|
131
|
+
# <deal-date type="date">2008-04-15</deal-date>
|
|
132
|
+
# ...
|
|
133
|
+
# </project>
|
|
134
|
+
# </projects>
|
|
135
|
+
#
|
|
136
|
+
# Otherwise the root element is "objects":
|
|
137
|
+
#
|
|
138
|
+
# [{ foo: 1, bar: 2}, { baz: 3}].to_xml
|
|
139
|
+
#
|
|
140
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
|
141
|
+
# <objects type="array">
|
|
142
|
+
# <object>
|
|
143
|
+
# <bar type="integer">2</bar>
|
|
144
|
+
# <foo type="integer">1</foo>
|
|
145
|
+
# </object>
|
|
146
|
+
# <object>
|
|
147
|
+
# <baz type="integer">3</baz>
|
|
148
|
+
# </object>
|
|
149
|
+
# </objects>
|
|
150
|
+
#
|
|
151
|
+
# If the collection is empty the root element is "nil-classes" by default:
|
|
152
|
+
#
|
|
153
|
+
# [].to_xml
|
|
154
|
+
#
|
|
155
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
|
156
|
+
# <nil-classes type="array"/>
|
|
157
|
+
#
|
|
158
|
+
# To ensure a meaningful root element use the <tt>:root</tt> option:
|
|
159
|
+
#
|
|
160
|
+
# customer_with_no_projects.projects.to_xml(root: 'projects')
|
|
161
|
+
#
|
|
162
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
|
163
|
+
# <projects type="array"/>
|
|
164
|
+
#
|
|
165
|
+
# By default name of the node for the children of root is <tt>root.singularize</tt>.
|
|
166
|
+
# You can change it with the <tt>:children</tt> option.
|
|
167
|
+
#
|
|
168
|
+
# The +options+ hash is passed downwards:
|
|
169
|
+
#
|
|
170
|
+
# Message.all.to_xml(skip_types: true)
|
|
171
|
+
#
|
|
172
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
|
173
|
+
# <messages>
|
|
174
|
+
# <message>
|
|
175
|
+
# <created-at>2008-03-07T09:58:18+01:00</created-at>
|
|
176
|
+
# <id>1</id>
|
|
177
|
+
# <name>1</name>
|
|
178
|
+
# <updated-at>2008-03-07T09:58:18+01:00</updated-at>
|
|
179
|
+
# <user-id>1</user-id>
|
|
180
|
+
# </message>
|
|
181
|
+
# </messages>
|
|
182
|
+
#
|
|
183
|
+
def to_xml(options = {})
|
|
184
|
+
require "active_support/builder" unless defined?(Builder::XmlMarkup)
|
|
185
|
+
|
|
186
|
+
options = options.dup
|
|
187
|
+
options[:indent] ||= 2
|
|
188
|
+
options[:builder] ||= Builder::XmlMarkup.new(indent: options[:indent])
|
|
189
|
+
options[:root] ||= \
|
|
190
|
+
if first.class != Hash && all?(first.class)
|
|
191
|
+
underscored = ActiveSupport::Inflector.underscore(first.class.name)
|
|
192
|
+
ActiveSupport::Inflector.pluralize(underscored).tr("/", "_")
|
|
193
|
+
else
|
|
194
|
+
"objects"
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
builder = options[:builder]
|
|
198
|
+
builder.instruct! unless options.delete(:skip_instruct)
|
|
199
|
+
|
|
200
|
+
root = ActiveSupport::XmlMini.rename_key(options[:root].to_s, options)
|
|
201
|
+
children = options.delete(:children) || root.singularize
|
|
202
|
+
attributes = options[:skip_types] ? {} : { type: "array" }
|
|
203
|
+
|
|
204
|
+
if empty?
|
|
205
|
+
builder.tag!(root, attributes)
|
|
206
|
+
else
|
|
207
|
+
builder.tag!(root, attributes) do
|
|
208
|
+
each { |value| ActiveSupport::XmlMini.to_tag(children, value, options) }
|
|
209
|
+
yield builder if block_given?
|
|
27
210
|
end
|
|
28
211
|
end
|
|
29
212
|
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Array
|
|
4
|
+
# Removes and returns the elements for which the block returns a true value.
|
|
5
|
+
# If no block is given, an Enumerator is returned instead.
|
|
6
|
+
#
|
|
7
|
+
# numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
8
|
+
# odd_numbers = numbers.extract! { |number| number.odd? } # => [1, 3, 5, 7, 9]
|
|
9
|
+
# numbers # => [0, 2, 4, 6, 8]
|
|
10
|
+
def extract!
|
|
11
|
+
return to_enum(:extract!) { size } unless block_given?
|
|
12
|
+
|
|
13
|
+
extracted_elements = []
|
|
14
|
+
|
|
15
|
+
reject! do |element|
|
|
16
|
+
extracted_elements << element if yield(element)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
extracted_elements
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Hash
|
|
4
|
+
# By default, only instances of Hash itself are extractable.
|
|
5
|
+
# Subclasses of Hash may implement this method and return
|
|
6
|
+
# true to declare themselves as extractable. If a Hash
|
|
7
|
+
# is extractable, Array#extract_options! pops it from
|
|
8
|
+
# the Array when it is the last element of the Array.
|
|
9
|
+
def extractable_options?
|
|
10
|
+
instance_of?(Hash)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class Array
|
|
15
|
+
# Extracts options from a set of arguments. Removes and returns the last
|
|
16
|
+
# element in the array if it's a hash, otherwise returns a blank hash.
|
|
17
|
+
#
|
|
18
|
+
# def options(*args)
|
|
19
|
+
# args.extract_options!
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# options(1, 2) # => {}
|
|
23
|
+
# options(1, 2, a: :b) # => {:a=>:b}
|
|
24
|
+
def extract_options!
|
|
25
|
+
if last.is_a?(Hash) && last.extractable_options?
|
|
26
|
+
pop
|
|
27
|
+
else
|
|
28
|
+
{}
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Array
|
|
4
|
+
# Splits or iterates over the array in groups of size +number+,
|
|
5
|
+
# padding any remaining slots with +fill_with+ unless it is +false+.
|
|
6
|
+
#
|
|
7
|
+
# %w(1 2 3 4 5 6 7 8 9 10).in_groups_of(3) {|group| p group}
|
|
8
|
+
# ["1", "2", "3"]
|
|
9
|
+
# ["4", "5", "6"]
|
|
10
|
+
# ["7", "8", "9"]
|
|
11
|
+
# ["10", nil, nil]
|
|
12
|
+
#
|
|
13
|
+
# %w(1 2 3 4 5).in_groups_of(2, ' ') {|group| p group}
|
|
14
|
+
# ["1", "2"]
|
|
15
|
+
# ["3", "4"]
|
|
16
|
+
# ["5", " "]
|
|
17
|
+
#
|
|
18
|
+
# %w(1 2 3 4 5).in_groups_of(2, false) {|group| p group}
|
|
19
|
+
# ["1", "2"]
|
|
20
|
+
# ["3", "4"]
|
|
21
|
+
# ["5"]
|
|
22
|
+
def in_groups_of(number, fill_with = nil, &block)
|
|
23
|
+
if number.to_i <= 0
|
|
24
|
+
raise ArgumentError,
|
|
25
|
+
"Group size must be a positive integer, was #{number.inspect}"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
if fill_with == false
|
|
29
|
+
collection = self
|
|
30
|
+
else
|
|
31
|
+
# size % number gives how many extra we have;
|
|
32
|
+
# subtracting from number gives how many to add;
|
|
33
|
+
# modulo number ensures we don't add group of just fill.
|
|
34
|
+
padding = (number - size % number) % number
|
|
35
|
+
collection = dup.concat(Array.new(padding, fill_with))
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
if block_given?
|
|
39
|
+
collection.each_slice(number, &block)
|
|
40
|
+
else
|
|
41
|
+
collection.each_slice(number).to_a
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Splits or iterates over the array in +number+ of groups, padding any
|
|
46
|
+
# remaining slots with +fill_with+ unless it is +false+.
|
|
47
|
+
#
|
|
48
|
+
# %w(1 2 3 4 5 6 7 8 9 10).in_groups(3) {|group| p group}
|
|
49
|
+
# ["1", "2", "3", "4"]
|
|
50
|
+
# ["5", "6", "7", nil]
|
|
51
|
+
# ["8", "9", "10", nil]
|
|
52
|
+
#
|
|
53
|
+
# %w(1 2 3 4 5 6 7 8 9 10).in_groups(3, ' ') {|group| p group}
|
|
54
|
+
# ["1", "2", "3", "4"]
|
|
55
|
+
# ["5", "6", "7", " "]
|
|
56
|
+
# ["8", "9", "10", " "]
|
|
57
|
+
#
|
|
58
|
+
# %w(1 2 3 4 5 6 7).in_groups(3, false) {|group| p group}
|
|
59
|
+
# ["1", "2", "3"]
|
|
60
|
+
# ["4", "5"]
|
|
61
|
+
# ["6", "7"]
|
|
62
|
+
def in_groups(number, fill_with = nil, &block)
|
|
63
|
+
# size.div number gives minor group size;
|
|
64
|
+
# size % number gives how many objects need extra accommodation;
|
|
65
|
+
# each group hold either division or division + 1 items.
|
|
66
|
+
division = size.div number
|
|
67
|
+
modulo = size % number
|
|
68
|
+
|
|
69
|
+
# create a new array avoiding dup
|
|
70
|
+
groups = []
|
|
71
|
+
start = 0
|
|
72
|
+
|
|
73
|
+
number.times do |index|
|
|
74
|
+
length = division + (modulo > 0 && modulo > index ? 1 : 0)
|
|
75
|
+
groups << last_group = slice(start, length)
|
|
76
|
+
last_group << fill_with if fill_with != false &&
|
|
77
|
+
modulo > 0 && length == division
|
|
78
|
+
start += length
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
if block_given?
|
|
82
|
+
groups.each(&block)
|
|
83
|
+
else
|
|
84
|
+
groups
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Divides the array into one or more subarrays based on a delimiting +value+
|
|
89
|
+
# or the result of an optional block.
|
|
90
|
+
#
|
|
91
|
+
# [1, 2, 3, 4, 5].split(3) # => [[1, 2], [4, 5]]
|
|
92
|
+
# (1..10).to_a.split { |i| i % 3 == 0 } # => [[1, 2], [4, 5], [7, 8], [10]]
|
|
93
|
+
def split(value = nil, &block)
|
|
94
|
+
arr = dup
|
|
95
|
+
result = []
|
|
96
|
+
if block_given?
|
|
97
|
+
while (idx = arr.index(&block))
|
|
98
|
+
result << arr.shift(idx)
|
|
99
|
+
arr.shift
|
|
100
|
+
end
|
|
101
|
+
else
|
|
102
|
+
while (idx = arr.index(value))
|
|
103
|
+
result << arr.shift(idx)
|
|
104
|
+
arr.shift
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
result << arr
|
|
108
|
+
end
|
|
109
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/array_inquirer"
|
|
4
|
+
|
|
5
|
+
class Array
|
|
6
|
+
# Wraps the array in an ActiveSupport::ArrayInquirer object, which gives a
|
|
7
|
+
# friendlier way to check its string-like contents.
|
|
8
|
+
#
|
|
9
|
+
# pets = [:cat, :dog].inquiry
|
|
10
|
+
#
|
|
11
|
+
# pets.cat? # => true
|
|
12
|
+
# pets.ferret? # => false
|
|
13
|
+
#
|
|
14
|
+
# pets.any?(:cat, :ferret) # => true
|
|
15
|
+
# pets.any?(:ferret, :alligator) # => false
|
|
16
|
+
def inquiry
|
|
17
|
+
ActiveSupport::ArrayInquirer.new(self)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Array
|
|
4
|
+
# Wraps its argument in an array unless it is already an array (or array-like).
|
|
5
|
+
#
|
|
6
|
+
# Specifically:
|
|
7
|
+
#
|
|
8
|
+
# * If the argument is +nil+ an empty array is returned.
|
|
9
|
+
# * Otherwise, if the argument responds to +to_ary+ it is invoked, and its result returned.
|
|
10
|
+
# * Otherwise, returns an array with the argument as its single element.
|
|
11
|
+
#
|
|
12
|
+
# Array.wrap(nil) # => []
|
|
13
|
+
# Array.wrap([1, 2, 3]) # => [1, 2, 3]
|
|
14
|
+
# Array.wrap(0) # => [0]
|
|
15
|
+
#
|
|
16
|
+
# This method is similar in purpose to <tt>Kernel#Array</tt>, but there are some differences:
|
|
17
|
+
#
|
|
18
|
+
# * If the argument responds to +to_ary+ the method is invoked. <tt>Kernel#Array</tt>
|
|
19
|
+
# moves on to try +to_a+ if the returned value is +nil+, but <tt>Array.wrap</tt> returns
|
|
20
|
+
# an array with the argument as its single element right away.
|
|
21
|
+
# * If the returned value from +to_ary+ is neither +nil+ nor an +Array+ object, <tt>Kernel#Array</tt>
|
|
22
|
+
# raises an exception, while <tt>Array.wrap</tt> does not, it just returns the value.
|
|
23
|
+
# * It does not call +to_a+ on the argument, if the argument does not respond to +to_ary+
|
|
24
|
+
# it returns an array with the argument as its single element.
|
|
25
|
+
#
|
|
26
|
+
# The last point is easily explained with some enumerables:
|
|
27
|
+
#
|
|
28
|
+
# Array(foo: :bar) # => [[:foo, :bar]]
|
|
29
|
+
# Array.wrap(foo: :bar) # => [{:foo=>:bar}]
|
|
30
|
+
#
|
|
31
|
+
# There's also a related idiom that uses the splat operator:
|
|
32
|
+
#
|
|
33
|
+
# [*object]
|
|
34
|
+
#
|
|
35
|
+
# which returns <tt>[]</tt> for +nil+, but calls to <tt>Array(object)</tt> otherwise.
|
|
36
|
+
#
|
|
37
|
+
# The differences with <tt>Kernel#Array</tt> explained above
|
|
38
|
+
# apply to the rest of <tt>object</tt>s.
|
|
39
|
+
def self.wrap(object)
|
|
40
|
+
if object.nil?
|
|
41
|
+
[]
|
|
42
|
+
elsif object.respond_to?(:to_ary)
|
|
43
|
+
object.to_ary || [object]
|
|
44
|
+
else
|
|
45
|
+
[object]
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
require_relative "array/wrap"
|
|
4
|
+
require_relative "array/access"
|
|
5
|
+
require_relative "array/conversions"
|
|
6
|
+
require_relative "array/extract"
|
|
7
|
+
require_relative "array/extract_options"
|
|
8
|
+
require_relative "array/grouping"
|
|
9
|
+
require_relative "array/inquiry"
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Remove this file from activesupport/lib/active_support/core_ext.rb when deleting the deprecation.
|
|
4
|
+
ActiveSupport.deprecator.warn <<~TEXT
|
|
5
|
+
active_support/core_ext/benchmark.rb is deprecated and will be removed in Rails 8.2 without replacement.
|
|
6
|
+
TEXT
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bigdecimal"
|
|
4
|
+
require "bigdecimal/util"
|
|
5
|
+
|
|
6
|
+
module ActiveSupport
|
|
7
|
+
module BigDecimalWithDefaultFormat # :nodoc:
|
|
8
|
+
def to_s(format = "F")
|
|
9
|
+
super(format)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
BigDecimal.prepend(ActiveSupport::BigDecimalWithDefaultFormat)
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/core_ext/module/redefine_method"
|
|
4
|
+
require "active_support/class_attribute"
|
|
5
|
+
|
|
6
|
+
class Class
|
|
7
|
+
# Declare a class-level attribute whose value is inheritable by subclasses.
|
|
8
|
+
# Subclasses can change their own value and it will not impact parent class.
|
|
9
|
+
#
|
|
10
|
+
# ==== Options
|
|
11
|
+
#
|
|
12
|
+
# * <tt>:instance_reader</tt> - Sets the instance reader method (defaults to true).
|
|
13
|
+
# * <tt>:instance_writer</tt> - Sets the instance writer method (defaults to true).
|
|
14
|
+
# * <tt>:instance_accessor</tt> - Sets both instance methods (defaults to true).
|
|
15
|
+
# * <tt>:instance_predicate</tt> - Sets a predicate method (defaults to true).
|
|
16
|
+
# * <tt>:default</tt> - Sets a default value for the attribute (defaults to nil).
|
|
17
|
+
#
|
|
18
|
+
# ==== Examples
|
|
19
|
+
#
|
|
20
|
+
# class Base
|
|
21
|
+
# class_attribute :setting
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
24
|
+
# class Subclass < Base
|
|
25
|
+
# end
|
|
26
|
+
#
|
|
27
|
+
# Base.setting = true
|
|
28
|
+
# Subclass.setting # => true
|
|
29
|
+
# Subclass.setting = false
|
|
30
|
+
# Subclass.setting # => false
|
|
31
|
+
# Base.setting # => true
|
|
32
|
+
#
|
|
33
|
+
# In the above case as long as Subclass does not assign a value to setting
|
|
34
|
+
# by performing <tt>Subclass.setting = _something_</tt>, <tt>Subclass.setting</tt>
|
|
35
|
+
# would read value assigned to parent class. Once Subclass assigns a value then
|
|
36
|
+
# the value assigned by Subclass would be returned.
|
|
37
|
+
#
|
|
38
|
+
# This matches normal Ruby method inheritance: think of writing an attribute
|
|
39
|
+
# on a subclass as overriding the reader method. However, you need to be aware
|
|
40
|
+
# when using +class_attribute+ with mutable structures as +Array+ or +Hash+.
|
|
41
|
+
# In such cases, you don't want to do changes in place. Instead use setters:
|
|
42
|
+
#
|
|
43
|
+
# Base.setting = []
|
|
44
|
+
# Base.setting # => []
|
|
45
|
+
# Subclass.setting # => []
|
|
46
|
+
#
|
|
47
|
+
# # Appending in child changes both parent and child because it is the same object:
|
|
48
|
+
# Subclass.setting << :foo
|
|
49
|
+
# Base.setting # => [:foo]
|
|
50
|
+
# Subclass.setting # => [:foo]
|
|
51
|
+
#
|
|
52
|
+
# # Use setters to not propagate changes:
|
|
53
|
+
# Base.setting = []
|
|
54
|
+
# Subclass.setting += [:foo]
|
|
55
|
+
# Base.setting # => []
|
|
56
|
+
# Subclass.setting # => [:foo]
|
|
57
|
+
#
|
|
58
|
+
# For convenience, an instance predicate method is defined as well.
|
|
59
|
+
# To skip it, pass <tt>instance_predicate: false</tt>.
|
|
60
|
+
#
|
|
61
|
+
# Subclass.setting? # => false
|
|
62
|
+
#
|
|
63
|
+
# Instances may overwrite the class value in the same way:
|
|
64
|
+
#
|
|
65
|
+
# Base.setting = true
|
|
66
|
+
# object = Base.new
|
|
67
|
+
# object.setting # => true
|
|
68
|
+
# object.setting = false
|
|
69
|
+
# object.setting # => false
|
|
70
|
+
# Base.setting # => true
|
|
71
|
+
#
|
|
72
|
+
# To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
|
|
73
|
+
#
|
|
74
|
+
# object.setting # => NoMethodError
|
|
75
|
+
# object.setting? # => NoMethodError
|
|
76
|
+
#
|
|
77
|
+
# To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
|
|
78
|
+
#
|
|
79
|
+
# object.setting = false # => NoMethodError
|
|
80
|
+
#
|
|
81
|
+
# To opt out of both instance methods, pass <tt>instance_accessor: false</tt>.
|
|
82
|
+
#
|
|
83
|
+
# To set a default value for the attribute, pass <tt>default:</tt>, like so:
|
|
84
|
+
#
|
|
85
|
+
# class_attribute :settings, default: {}
|
|
86
|
+
def class_attribute(*attrs, instance_accessor: true,
|
|
87
|
+
instance_reader: instance_accessor, instance_writer: instance_accessor, instance_predicate: true, default: nil
|
|
88
|
+
)
|
|
89
|
+
class_methods, methods = [], []
|
|
90
|
+
attrs.each do |name|
|
|
91
|
+
unless name.is_a?(Symbol) || name.is_a?(String)
|
|
92
|
+
raise TypeError, "#{name.inspect} is not a symbol nor a string"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
name = name.to_sym
|
|
96
|
+
namespaced_name = :"__class_attr_#{name}"
|
|
97
|
+
::ActiveSupport::ClassAttribute.redefine(self, name, namespaced_name, default)
|
|
98
|
+
|
|
99
|
+
class_methods << "def #{name}; #{namespaced_name}; end"
|
|
100
|
+
class_methods << "def #{name}=(value); self.#{namespaced_name} = value; end"
|
|
101
|
+
|
|
102
|
+
if singleton_class?
|
|
103
|
+
methods << <<~RUBY if instance_reader
|
|
104
|
+
silence_redefinition_of_method(:#{name})
|
|
105
|
+
def #{name}
|
|
106
|
+
self.singleton_class.#{name}
|
|
107
|
+
end
|
|
108
|
+
RUBY
|
|
109
|
+
else
|
|
110
|
+
methods << <<~RUBY if instance_reader
|
|
111
|
+
silence_redefinition_of_method def #{name}
|
|
112
|
+
if defined?(@#{name})
|
|
113
|
+
@#{name}
|
|
114
|
+
else
|
|
115
|
+
self.class.#{name}
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
RUBY
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
methods << <<~RUBY if instance_writer
|
|
122
|
+
silence_redefinition_of_method(:#{name}=)
|
|
123
|
+
attr_writer :#{name}
|
|
124
|
+
RUBY
|
|
125
|
+
|
|
126
|
+
if instance_predicate
|
|
127
|
+
class_methods << "silence_redefinition_of_method def #{name}?; !!self.#{name}; end"
|
|
128
|
+
if instance_reader
|
|
129
|
+
methods << "silence_redefinition_of_method def #{name}?; !!self.#{name}; end"
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
location = caller_locations(1, 1).first
|
|
135
|
+
class_eval(["class << self", *class_methods, "end", *methods].join(";").tr("\n", ";"), location.path, location.lineno)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# cattr_* became mattr_* aliases in 7dfbd91b0780fbd6a1dd9bfbc176e10894871d2d,
|
|
4
|
+
# but we keep this around for libraries that directly require it knowing they
|
|
5
|
+
# want cattr_*. No need to deprecate.
|
|
6
|
+
require "active_support/core_ext/module/attribute_accessors"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/descendants_tracker"
|
|
4
|
+
|
|
5
|
+
class Class
|
|
6
|
+
# Returns an array with all classes that are < than its receiver.
|
|
7
|
+
#
|
|
8
|
+
# class C; end
|
|
9
|
+
# C.descendants # => []
|
|
10
|
+
#
|
|
11
|
+
# class B < C; end
|
|
12
|
+
# C.descendants # => [B]
|
|
13
|
+
#
|
|
14
|
+
# class A < B; end
|
|
15
|
+
# C.descendants # => [B, A]
|
|
16
|
+
#
|
|
17
|
+
# class D < C; end
|
|
18
|
+
# C.descendants # => [B, A, D]
|
|
19
|
+
def descendants
|
|
20
|
+
subclasses.concat(subclasses.flat_map(&:descendants))
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
prepend ActiveSupport::DescendantsTracker::ReloadedClassesFiltering
|
|
24
|
+
end
|