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,166 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
# A singleton instance of this class is yielded by Inflector.inflections, which can then be used to specify additional
|
|
8
|
-
# inflection rules. Examples:
|
|
9
|
-
#
|
|
10
|
-
# Inflector.inflections do |inflect|
|
|
11
|
-
# inflect.plural /^(ox)$/i, '\1\2en'
|
|
12
|
-
# inflect.singular /^(ox)en/i, '\1'
|
|
13
|
-
#
|
|
14
|
-
# inflect.irregular 'octopus', 'octopi'
|
|
15
|
-
#
|
|
16
|
-
# inflect.uncountable "equipment"
|
|
17
|
-
# end
|
|
18
|
-
#
|
|
19
|
-
# New rules are added at the top. So in the example above, the irregular rule for octopus will now be the first of the
|
|
20
|
-
# pluralization and singularization rules that is runs. This guarantees that your rules run before any of the rules that may
|
|
21
|
-
# already have been loaded.
|
|
22
|
-
class Inflections
|
|
23
|
-
include Singleton
|
|
24
|
-
|
|
25
|
-
attr_reader :plurals, :singulars, :uncountables
|
|
26
|
-
|
|
27
|
-
def initialize
|
|
28
|
-
@plurals, @singulars, @uncountables = [], [], []
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# Specifies a new pluralization rule and its replacement. The rule can either be a string or a regular expression.
|
|
32
|
-
# The replacement should always be a string that may include references to the matched data from the rule.
|
|
33
|
-
def plural(rule, replacement)
|
|
34
|
-
@plurals.insert(0, [rule, replacement])
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Specifies a new singularization rule and its replacement. The rule can either be a string or a regular expression.
|
|
38
|
-
# The replacement should always be a string that may include references to the matched data from the rule.
|
|
39
|
-
def singular(rule, replacement)
|
|
40
|
-
@singulars.insert(0, [rule, replacement])
|
|
41
|
-
end
|
|
3
|
+
# in case active_support/inflector is required without the rest of active_support
|
|
4
|
+
require "active_support/inflector/inflections"
|
|
5
|
+
require "active_support/inflector/transliterate"
|
|
6
|
+
require "active_support/inflector/methods"
|
|
42
7
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
#
|
|
46
|
-
# Examples:
|
|
47
|
-
# irregular 'octopus', 'octopi'
|
|
48
|
-
# irregular 'person', 'people'
|
|
49
|
-
def irregular(singular, plural)
|
|
50
|
-
plural(Regexp.new("(#{singular[0,1]})#{singular[1..-1]}$", "i"), '\1' + plural[1..-1])
|
|
51
|
-
singular(Regexp.new("(#{plural[0,1]})#{plural[1..-1]}$", "i"), '\1' + singular[1..-1])
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# Add uncountable words that shouldn't be attempted inflected.
|
|
55
|
-
#
|
|
56
|
-
# Examples:
|
|
57
|
-
# uncountable "money"
|
|
58
|
-
# uncountable "money", "information"
|
|
59
|
-
# uncountable %w( money information rice )
|
|
60
|
-
def uncountable(*words)
|
|
61
|
-
(@uncountables << words).flatten!
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
# Clears the loaded inflections within a given scope (default is :all). Give the scope as a symbol of the inflection type,
|
|
65
|
-
# the options are: :plurals, :singulars, :uncountables
|
|
66
|
-
#
|
|
67
|
-
# Examples:
|
|
68
|
-
# clear :all
|
|
69
|
-
# clear :plurals
|
|
70
|
-
def clear(scope = :all)
|
|
71
|
-
case scope
|
|
72
|
-
when :all
|
|
73
|
-
@plurals, @singulars, @uncountables = [], [], []
|
|
74
|
-
else
|
|
75
|
-
instance_variable_set "@#{scope}", []
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
extend self
|
|
81
|
-
|
|
82
|
-
def inflections
|
|
83
|
-
if block_given?
|
|
84
|
-
yield Inflections.instance
|
|
85
|
-
else
|
|
86
|
-
Inflections.instance
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def pluralize(word)
|
|
91
|
-
result = word.to_s.dup
|
|
92
|
-
|
|
93
|
-
if inflections.uncountables.include?(result.downcase)
|
|
94
|
-
result
|
|
95
|
-
else
|
|
96
|
-
inflections.plurals.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
|
|
97
|
-
result
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def singularize(word)
|
|
102
|
-
result = word.to_s.dup
|
|
103
|
-
|
|
104
|
-
if inflections.uncountables.include?(result.downcase)
|
|
105
|
-
result
|
|
106
|
-
else
|
|
107
|
-
inflections.singulars.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
|
|
108
|
-
result
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
def camelize(lower_case_and_underscored_word)
|
|
113
|
-
lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
def titleize(word)
|
|
117
|
-
humanize(underscore(word)).gsub(/\b([a-z])/) { $1.capitalize }
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
def underscore(camel_cased_word)
|
|
121
|
-
camel_cased_word.to_s.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').downcase
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def humanize(lower_case_and_underscored_word)
|
|
125
|
-
lower_case_and_underscored_word.to_s.gsub(/_id$/, "").gsub(/_/, " ").capitalize
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
def demodulize(class_name_in_module)
|
|
129
|
-
class_name_in_module.to_s.gsub(/^.*::/, '')
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
def tableize(class_name)
|
|
133
|
-
pluralize(underscore(class_name))
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
def classify(table_name)
|
|
137
|
-
camelize(singularize(table_name))
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
|
|
141
|
-
underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id")
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def constantize(camel_cased_word)
|
|
145
|
-
raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!" unless
|
|
146
|
-
camel_cased_word.split("::").all? { |part| /^[A-Z]\w*$/ =~ part }
|
|
147
|
-
|
|
148
|
-
camel_cased_word = "::#{camel_cased_word}" unless camel_cased_word[0, 2] == '::'
|
|
149
|
-
Object.module_eval(camel_cased_word, __FILE__, __LINE__)
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def ordinalize(number)
|
|
153
|
-
if (11..13).include?(number.to_i % 100)
|
|
154
|
-
"#{number}th"
|
|
155
|
-
else
|
|
156
|
-
case number.to_i % 10
|
|
157
|
-
when 1: "#{number}st"
|
|
158
|
-
when 2: "#{number}nd"
|
|
159
|
-
when 3: "#{number}rd"
|
|
160
|
-
else "#{number}th"
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
|
-
end
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
require File.dirname(__FILE__) + '/inflections'
|
|
8
|
+
require "active_support/inflections"
|
|
9
|
+
require "active_support/core_ext/string/inflections"
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveSupport
|
|
4
|
+
module IsolatedExecutionState # :nodoc:
|
|
5
|
+
@isolation_level = nil
|
|
6
|
+
|
|
7
|
+
Thread.attr_accessor :active_support_execution_state
|
|
8
|
+
Fiber.attr_accessor :active_support_execution_state
|
|
9
|
+
|
|
10
|
+
class << self
|
|
11
|
+
attr_reader :isolation_level, :scope
|
|
12
|
+
|
|
13
|
+
def isolation_level=(level)
|
|
14
|
+
return if level == @isolation_level
|
|
15
|
+
|
|
16
|
+
unless %i(thread fiber).include?(level)
|
|
17
|
+
raise ArgumentError, "isolation_level must be `:thread` or `:fiber`, got: `#{level.inspect}`"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
clear if @isolation_level
|
|
21
|
+
|
|
22
|
+
@scope =
|
|
23
|
+
case level
|
|
24
|
+
when :thread; Thread
|
|
25
|
+
when :fiber; Fiber
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
@isolation_level = level
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def [](key)
|
|
32
|
+
if state = @scope.current.active_support_execution_state
|
|
33
|
+
state[key]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def []=(key, value)
|
|
38
|
+
state = (@scope.current.active_support_execution_state ||= {})
|
|
39
|
+
state[key] = value
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def key?(key)
|
|
43
|
+
@scope.current.active_support_execution_state&.key?(key)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def delete(key)
|
|
47
|
+
@scope.current.active_support_execution_state&.delete(key)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def clear
|
|
51
|
+
@scope.current.active_support_execution_state&.clear
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def context
|
|
55
|
+
scope.current
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def share_with(other, except: [], &block)
|
|
59
|
+
# Action Controller streaming spawns a new thread and copy thread locals.
|
|
60
|
+
# We do the same here for backward compatibility, but this is very much a hack
|
|
61
|
+
# and streaming should be rethought.
|
|
62
|
+
if state = other.active_support_execution_state
|
|
63
|
+
copied_state = state.dup
|
|
64
|
+
Array(except).each { |key| copied_state.delete(key) }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
old_state, context.active_support_execution_state = context.active_support_execution_state, copied_state
|
|
68
|
+
block.call
|
|
69
|
+
ensure
|
|
70
|
+
context.active_support_execution_state = old_state
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
self.isolation_level = :thread
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/core_ext/module/attribute_accessors"
|
|
4
|
+
require "active_support/core_ext/module/delegation"
|
|
5
|
+
require "json"
|
|
6
|
+
|
|
7
|
+
module ActiveSupport
|
|
8
|
+
# Look for and parse JSON strings that look like ISO 8601 times.
|
|
9
|
+
mattr_accessor :parse_json_times
|
|
10
|
+
|
|
11
|
+
module JSON
|
|
12
|
+
# matches YAML-formatted dates
|
|
13
|
+
DATE_REGEX = /\A\d{4}-\d{2}-\d{2}\z/
|
|
14
|
+
DATETIME_REGEX = /\A(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[T \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?)?)\z/
|
|
15
|
+
|
|
16
|
+
class << self
|
|
17
|
+
# Parses a JSON string (JavaScript Object Notation) into a Ruby object.
|
|
18
|
+
# See http://www.json.org for more info.
|
|
19
|
+
#
|
|
20
|
+
# ActiveSupport::JSON.decode("{\"team\":\"rails\",\"players\":\"36\"}")
|
|
21
|
+
# # => {"team" => "rails", "players" => "36"}
|
|
22
|
+
# ActiveSupport::JSON.decode("2.39")
|
|
23
|
+
# # => 2.39
|
|
24
|
+
def decode(json, options = {})
|
|
25
|
+
data = ::JSON.parse(json, options)
|
|
26
|
+
|
|
27
|
+
if ActiveSupport.parse_json_times
|
|
28
|
+
convert_dates_from(data)
|
|
29
|
+
else
|
|
30
|
+
data
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
alias_method :load, :decode
|
|
34
|
+
|
|
35
|
+
# Returns the class of the error that will be raised when there is an
|
|
36
|
+
# error in decoding JSON. Using this method means you won't directly
|
|
37
|
+
# depend on the ActiveSupport's JSON implementation, in case it changes
|
|
38
|
+
# in the future.
|
|
39
|
+
#
|
|
40
|
+
# begin
|
|
41
|
+
# obj = ActiveSupport::JSON.decode(some_string)
|
|
42
|
+
# rescue ActiveSupport::JSON.parse_error
|
|
43
|
+
# Rails.logger.warn("Attempted to decode invalid JSON: #{some_string}")
|
|
44
|
+
# end
|
|
45
|
+
def parse_error
|
|
46
|
+
::JSON::ParserError
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
def convert_dates_from(data)
|
|
51
|
+
case data
|
|
52
|
+
when nil
|
|
53
|
+
nil
|
|
54
|
+
when DATE_REGEX
|
|
55
|
+
begin
|
|
56
|
+
Date.parse(data)
|
|
57
|
+
rescue ArgumentError
|
|
58
|
+
data
|
|
59
|
+
end
|
|
60
|
+
when DATETIME_REGEX
|
|
61
|
+
begin
|
|
62
|
+
Time.zone.parse(data)
|
|
63
|
+
rescue ArgumentError
|
|
64
|
+
data
|
|
65
|
+
end
|
|
66
|
+
when Array
|
|
67
|
+
data.map! { |d| convert_dates_from(d) }
|
|
68
|
+
when Hash
|
|
69
|
+
data.transform_values! do |value|
|
|
70
|
+
convert_dates_from(value)
|
|
71
|
+
end
|
|
72
|
+
else
|
|
73
|
+
data
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/core_ext/object/json"
|
|
4
|
+
require "active_support/core_ext/module/delegation"
|
|
5
|
+
|
|
6
|
+
module ActiveSupport
|
|
7
|
+
class << self
|
|
8
|
+
delegate :use_standard_json_time_format, :use_standard_json_time_format=,
|
|
9
|
+
:time_precision, :time_precision=,
|
|
10
|
+
:escape_html_entities_in_json, :escape_html_entities_in_json=,
|
|
11
|
+
:escape_js_separators_in_json, :escape_js_separators_in_json=,
|
|
12
|
+
:json_encoder, :json_encoder=,
|
|
13
|
+
to: :'ActiveSupport::JSON::Encoding'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
module JSON
|
|
17
|
+
class << self
|
|
18
|
+
# Dumps objects in JSON (JavaScript Object Notation).
|
|
19
|
+
# See http://www.json.org for more info.
|
|
20
|
+
#
|
|
21
|
+
# ActiveSupport::JSON.encode({ team: 'rails', players: '36' })
|
|
22
|
+
# # => "{\"team\":\"rails\",\"players\":\"36\"}"
|
|
23
|
+
#
|
|
24
|
+
# By default, it generates JSON that is safe to include in JavaScript, as
|
|
25
|
+
# it escapes U+2028 (Line Separator) and U+2029 (Paragraph Separator):
|
|
26
|
+
#
|
|
27
|
+
# ActiveSupport::JSON.encode({ key: "\u2028" })
|
|
28
|
+
# # => "{\"key\":\"\\u2028\"}"
|
|
29
|
+
#
|
|
30
|
+
# By default, it also generates JSON that is safe to include in HTML, as
|
|
31
|
+
# it escapes <tt><</tt>, <tt>></tt>, and <tt>&</tt>:
|
|
32
|
+
#
|
|
33
|
+
# ActiveSupport::JSON.encode({ key: "<>&" })
|
|
34
|
+
# # => "{\"key\":\"\\u003c\\u003e\\u0026\"}"
|
|
35
|
+
#
|
|
36
|
+
# This behavior can be changed with the +escape_html_entities+ option, or the
|
|
37
|
+
# global escape_html_entities_in_json configuration option.
|
|
38
|
+
#
|
|
39
|
+
# ActiveSupport::JSON.encode({ key: "<>&" }, escape_html_entities: false)
|
|
40
|
+
# # => "{\"key\":\"<>&\"}"
|
|
41
|
+
#
|
|
42
|
+
# For performance reasons, you can set the +escape+ option to false,
|
|
43
|
+
# which will skip all escaping:
|
|
44
|
+
#
|
|
45
|
+
# ActiveSupport::JSON.encode({ key: "\u2028<>&" }, escape: false)
|
|
46
|
+
# # => "{\"key\":\"\u2028<>&\"}"
|
|
47
|
+
def encode(value, options = nil)
|
|
48
|
+
if options.nil? || options.empty?
|
|
49
|
+
Encoding.encode_without_options(value)
|
|
50
|
+
elsif options == { escape: false }.freeze
|
|
51
|
+
Encoding.encode_without_escape(value)
|
|
52
|
+
else
|
|
53
|
+
Encoding.json_encoder.new(options).encode(value)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
alias_method :dump, :encode
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
module Encoding # :nodoc:
|
|
60
|
+
U2028 = -"\u2028".b
|
|
61
|
+
U2029 = -"\u2029".b
|
|
62
|
+
|
|
63
|
+
ESCAPED_CHARS = {
|
|
64
|
+
U2028 => '\u2028'.b,
|
|
65
|
+
U2029 => '\u2029'.b,
|
|
66
|
+
">".b => '\u003e'.b,
|
|
67
|
+
"<".b => '\u003c'.b,
|
|
68
|
+
"&".b => '\u0026'.b,
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
HTML_ENTITIES_REGEX = Regexp.union(*(ESCAPED_CHARS.keys - [U2028, U2029]))
|
|
72
|
+
FULL_ESCAPE_REGEX = Regexp.union(*ESCAPED_CHARS.keys)
|
|
73
|
+
JS_SEPARATORS_REGEX = Regexp.union(U2028, U2029)
|
|
74
|
+
|
|
75
|
+
class JSONGemEncoder # :nodoc:
|
|
76
|
+
attr_reader :options
|
|
77
|
+
|
|
78
|
+
def initialize(options = nil)
|
|
79
|
+
@options = options || {}
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Encode the given object into a JSON string
|
|
83
|
+
def encode(value)
|
|
84
|
+
unless options.empty?
|
|
85
|
+
value = value.as_json(options.dup.freeze)
|
|
86
|
+
end
|
|
87
|
+
json = stringify(jsonify(value))
|
|
88
|
+
|
|
89
|
+
return json unless @options.fetch(:escape, true)
|
|
90
|
+
|
|
91
|
+
json.force_encoding(::Encoding::BINARY)
|
|
92
|
+
if @options.fetch(:escape_html_entities, Encoding.escape_html_entities_in_json)
|
|
93
|
+
if Encoding.escape_js_separators_in_json
|
|
94
|
+
json.gsub!(FULL_ESCAPE_REGEX, ESCAPED_CHARS)
|
|
95
|
+
else
|
|
96
|
+
json.gsub!(HTML_ENTITIES_REGEX, ESCAPED_CHARS)
|
|
97
|
+
end
|
|
98
|
+
elsif Encoding.escape_js_separators_in_json
|
|
99
|
+
json.gsub!(JS_SEPARATORS_REGEX, ESCAPED_CHARS)
|
|
100
|
+
end
|
|
101
|
+
json.force_encoding(::Encoding::UTF_8)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
private
|
|
105
|
+
# Convert an object into a "JSON-ready" representation composed of
|
|
106
|
+
# primitives like Hash, Array, String, Symbol, Numeric,
|
|
107
|
+
# and +true+/+false+/+nil+.
|
|
108
|
+
# Recursively calls #as_json to the object to recursively build a
|
|
109
|
+
# fully JSON-ready object.
|
|
110
|
+
#
|
|
111
|
+
# This allows developers to implement #as_json without having to
|
|
112
|
+
# worry about what base types of objects they are allowed to return
|
|
113
|
+
# or having to remember to call #as_json recursively.
|
|
114
|
+
#
|
|
115
|
+
# Note: the +options+ hash passed to +object.to_json+ is only passed
|
|
116
|
+
# to +object.as_json+, not any of this method's recursive +#as_json+
|
|
117
|
+
# calls.
|
|
118
|
+
def jsonify(value)
|
|
119
|
+
case value
|
|
120
|
+
when String, Integer, Symbol, nil, true, false
|
|
121
|
+
value
|
|
122
|
+
when Numeric
|
|
123
|
+
value.as_json
|
|
124
|
+
when Hash
|
|
125
|
+
result = {}
|
|
126
|
+
value.each do |k, v|
|
|
127
|
+
k = k.to_s unless Symbol === k || String === k
|
|
128
|
+
result[k] = jsonify(v)
|
|
129
|
+
end
|
|
130
|
+
result
|
|
131
|
+
when Array
|
|
132
|
+
value.map { |v| jsonify(v) }
|
|
133
|
+
else
|
|
134
|
+
if defined?(::JSON::Fragment) && ::JSON::Fragment === value
|
|
135
|
+
value
|
|
136
|
+
else
|
|
137
|
+
jsonify value.as_json
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Encode a "jsonified" Ruby data structure using the JSON gem
|
|
143
|
+
def stringify(jsonified)
|
|
144
|
+
::JSON.generate(jsonified)
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# ruby/json 2.14.x yields non-String keys but doesn't let us know it's a key
|
|
149
|
+
if defined?(::JSON::Coder) && Gem::Version.new(::JSON::VERSION) >= Gem::Version.new("2.15.2")
|
|
150
|
+
class JSONGemCoderEncoder # :nodoc:
|
|
151
|
+
JSON_NATIVE_TYPES = [Hash, Array, Float, String, Symbol, Integer, NilClass, TrueClass, FalseClass, ::JSON::Fragment].freeze
|
|
152
|
+
CODER = ::JSON::Coder.new do |value, is_key|
|
|
153
|
+
json_value = value.as_json
|
|
154
|
+
# Keep compatibility by calling to_s on non-String keys
|
|
155
|
+
next json_value.to_s if is_key
|
|
156
|
+
# Handle objects returning self from as_json
|
|
157
|
+
if json_value.equal?(value)
|
|
158
|
+
next ::JSON::Fragment.new(::JSON.generate(json_value))
|
|
159
|
+
end
|
|
160
|
+
# Handle objects not returning JSON-native types from as_json
|
|
161
|
+
count = 5
|
|
162
|
+
until JSON_NATIVE_TYPES.include?(json_value.class)
|
|
163
|
+
raise SystemStackError if count == 0
|
|
164
|
+
json_value = json_value.as_json
|
|
165
|
+
count -= 1
|
|
166
|
+
end
|
|
167
|
+
json_value
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def initialize(options = nil)
|
|
172
|
+
if options
|
|
173
|
+
options = options.dup
|
|
174
|
+
@escape = options.delete(:escape) { true }
|
|
175
|
+
@options = options.freeze
|
|
176
|
+
else
|
|
177
|
+
@escape = true
|
|
178
|
+
@options = {}.freeze
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Encode the given object into a JSON string
|
|
183
|
+
def encode(value)
|
|
184
|
+
value = value.as_json(@options) unless @options.empty?
|
|
185
|
+
|
|
186
|
+
json = CODER.dump(value)
|
|
187
|
+
|
|
188
|
+
return json unless @escape
|
|
189
|
+
|
|
190
|
+
json.force_encoding(::Encoding::BINARY)
|
|
191
|
+
if @options.fetch(:escape_html_entities, Encoding.escape_html_entities_in_json)
|
|
192
|
+
if Encoding.escape_js_separators_in_json
|
|
193
|
+
json.gsub!(FULL_ESCAPE_REGEX, ESCAPED_CHARS)
|
|
194
|
+
else
|
|
195
|
+
json.gsub!(HTML_ENTITIES_REGEX, ESCAPED_CHARS)
|
|
196
|
+
end
|
|
197
|
+
elsif Encoding.escape_js_separators_in_json
|
|
198
|
+
json.gsub!(JS_SEPARATORS_REGEX, ESCAPED_CHARS)
|
|
199
|
+
end
|
|
200
|
+
json.force_encoding(::Encoding::UTF_8)
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
class << self
|
|
206
|
+
# If true, use ISO 8601 format for dates and times. Otherwise, fall back
|
|
207
|
+
# to the Active Support legacy format.
|
|
208
|
+
attr_accessor :use_standard_json_time_format
|
|
209
|
+
|
|
210
|
+
# If true, encode >, <, & as escaped unicode sequences (e.g. > as \u003e)
|
|
211
|
+
# as a safety measure.
|
|
212
|
+
attr_accessor :escape_html_entities_in_json
|
|
213
|
+
|
|
214
|
+
# If true, encode LINE SEPARATOR (U+2028) and PARAGRAPH SEPARATOR (U+2029)
|
|
215
|
+
# as escaped unicode sequences ('\u2028' and '\u2029').
|
|
216
|
+
# Historically these characters were not valid inside JavaScript strings
|
|
217
|
+
# but that changed in ECMAScript 2019. As such it's no longer a concern in
|
|
218
|
+
# modern browsers: https://caniuse.com/mdn-javascript_builtins_json_json_superset.
|
|
219
|
+
attr_accessor :escape_js_separators_in_json
|
|
220
|
+
|
|
221
|
+
# Sets the precision of encoded time values.
|
|
222
|
+
# Defaults to 3 (equivalent to millisecond precision)
|
|
223
|
+
attr_accessor :time_precision
|
|
224
|
+
|
|
225
|
+
# Sets the encoder used by \Rails to encode Ruby objects into JSON strings
|
|
226
|
+
# in +Object#to_json+ and +ActiveSupport::JSON.encode+.
|
|
227
|
+
attr_reader :json_encoder
|
|
228
|
+
|
|
229
|
+
def json_encoder=(encoder)
|
|
230
|
+
@json_encoder = encoder
|
|
231
|
+
@encoder_without_options = encoder.new
|
|
232
|
+
@encoder_without_escape = encoder.new(escape: false)
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def encode_without_options(value) # :nodoc:
|
|
236
|
+
@encoder_without_options.encode(value)
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def encode_without_escape(value) # :nodoc:
|
|
240
|
+
@encoder_without_escape.encode(value)
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
self.use_standard_json_time_format = true
|
|
245
|
+
self.escape_html_entities_in_json = true
|
|
246
|
+
self.escape_js_separators_in_json = true
|
|
247
|
+
self.json_encoder =
|
|
248
|
+
if defined?(JSONGemCoderEncoder)
|
|
249
|
+
JSONGemCoderEncoder
|
|
250
|
+
else
|
|
251
|
+
JSONGemEncoder
|
|
252
|
+
end
|
|
253
|
+
self.time_precision = 3
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "concurrent/map"
|
|
4
|
+
require "openssl"
|
|
5
|
+
|
|
6
|
+
module ActiveSupport
|
|
7
|
+
# = Key Generator
|
|
8
|
+
#
|
|
9
|
+
# KeyGenerator is a simple wrapper around OpenSSL's implementation of PBKDF2.
|
|
10
|
+
# It can be used to derive a number of keys for various purposes from a given secret.
|
|
11
|
+
# This lets \Rails applications have a single secure secret, but avoid reusing that
|
|
12
|
+
# key in multiple incompatible contexts.
|
|
13
|
+
class KeyGenerator
|
|
14
|
+
class << self
|
|
15
|
+
def hash_digest_class=(klass)
|
|
16
|
+
if klass.kind_of?(Class) && klass < OpenSSL::Digest
|
|
17
|
+
@hash_digest_class = klass
|
|
18
|
+
else
|
|
19
|
+
raise ArgumentError, "#{klass} is expected to be an OpenSSL::Digest subclass"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def hash_digest_class
|
|
24
|
+
@hash_digest_class ||= OpenSSL::Digest::SHA1
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def initialize(secret, options = {})
|
|
29
|
+
@secret = secret
|
|
30
|
+
# The default iterations are higher than required for our key derivation uses
|
|
31
|
+
# on the off chance someone uses this for password storage
|
|
32
|
+
@iterations = options[:iterations] || 2**16
|
|
33
|
+
# Also allow configuration here so people can use this to build a rotation
|
|
34
|
+
# scheme when switching the digest class.
|
|
35
|
+
@hash_digest_class = options[:hash_digest_class] || self.class.hash_digest_class
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Returns a derived key suitable for use. The default +key_size+ is chosen
|
|
39
|
+
# to be compatible with the default settings of ActiveSupport::MessageVerifier.
|
|
40
|
+
# i.e. <tt>OpenSSL::Digest::SHA1#block_length</tt>
|
|
41
|
+
def generate_key(salt, key_size = 64)
|
|
42
|
+
OpenSSL::PKCS5.pbkdf2_hmac(@secret, salt, @iterations, key_size, @hash_digest_class.new)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def inspect # :nodoc:
|
|
46
|
+
"#<#{self.class.name}:#{'%#016x' % (object_id << 1)}>"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# = Caching Key Generator
|
|
51
|
+
#
|
|
52
|
+
# CachingKeyGenerator is a wrapper around KeyGenerator which allows users to avoid
|
|
53
|
+
# re-executing the key generation process when it's called using the same +salt+ and
|
|
54
|
+
# +key_size+.
|
|
55
|
+
class CachingKeyGenerator
|
|
56
|
+
def initialize(key_generator)
|
|
57
|
+
@key_generator = key_generator
|
|
58
|
+
@cache_keys = Concurrent::Map.new
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Returns a derived key suitable for use.
|
|
62
|
+
def generate_key(*args)
|
|
63
|
+
@cache_keys[args.join("|")] ||= @key_generator.generate_key(*args)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|