activesupport 4.0.12 → 7.0.2.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +249 -501
- data/MIT-LICENSE +2 -2
- data/README.rdoc +10 -5
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/all.rb +5 -3
- data/lib/active_support/array_inquirer.rb +48 -0
- data/lib/active_support/backtrace_cleaner.rb +41 -13
- data/lib/active_support/benchmarkable.rb +7 -15
- data/lib/active_support/builder.rb +3 -1
- data/lib/active_support/cache/file_store.rb +96 -74
- data/lib/active_support/cache/mem_cache_store.rb +211 -103
- data/lib/active_support/cache/memory_store.rb +90 -58
- data/lib/active_support/cache/null_store.rb +19 -7
- data/lib/active_support/cache/redis_cache_store.rb +468 -0
- data/lib/active_support/cache/strategy/local_cache.rb +86 -83
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
- data/lib/active_support/cache.rb +580 -241
- data/lib/active_support/callbacks.rb +812 -425
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +103 -14
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +33 -0
- data/lib/active_support/concurrency/share_lock.rb +226 -0
- data/lib/active_support/configurable.rb +21 -19
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/array/access.rb +47 -1
- data/lib/active_support/core_ext/array/conversions.rb +35 -44
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array/extract_options.rb +2 -0
- data/lib/active_support/core_ext/array/grouping.rb +26 -16
- data/lib/active_support/core_ext/array/inquiry.rb +19 -0
- data/lib/active_support/core_ext/array/wrap.rb +7 -4
- data/lib/active_support/core_ext/array.rb +10 -7
- data/lib/active_support/core_ext/benchmark.rb +5 -3
- data/lib/active_support/core_ext/big_decimal/conversions.rb +9 -26
- data/lib/active_support/core_ext/big_decimal.rb +3 -1
- data/lib/active_support/core_ext/class/attribute.rb +52 -49
- data/lib/active_support/core_ext/class/attribute_accessors.rb +5 -169
- data/lib/active_support/core_ext/class/subclasses.rb +25 -26
- data/lib/active_support/core_ext/class.rb +4 -4
- data/lib/active_support/core_ext/date/acts_like.rb +3 -1
- data/lib/active_support/core_ext/date/blank.rb +14 -0
- data/lib/active_support/core_ext/date/calculations.rb +31 -18
- data/lib/active_support/core_ext/date/conversions.rb +43 -32
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/date/zones.rb +5 -34
- data/lib/active_support/core_ext/date.rb +7 -4
- data/lib/active_support/core_ext/date_and_time/calculations.rb +198 -66
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +31 -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 +4 -2
- data/lib/active_support/core_ext/date_time/blank.rb +14 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +79 -38
- data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +31 -26
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/date_time.rb +8 -4
- data/lib/active_support/core_ext/digest/uuid.rb +79 -0
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +249 -17
- data/lib/active_support/core_ext/file/atomic.rb +41 -32
- data/lib/active_support/core_ext/file.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +71 -49
- data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +14 -5
- data/lib/active_support/core_ext/hash/indifferent_access.rb +5 -3
- data/lib/active_support/core_ext/hash/keys.rb +39 -56
- data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
- data/lib/active_support/core_ext/hash/slice.rb +8 -23
- data/lib/active_support/core_ext/hash.rb +10 -8
- data/lib/active_support/core_ext/integer/inflections.rb +3 -1
- data/lib/active_support/core_ext/integer/multiple.rb +3 -1
- data/lib/active_support/core_ext/integer/time.rb +11 -33
- data/lib/active_support/core_ext/integer.rb +5 -3
- data/lib/active_support/core_ext/kernel/concern.rb +14 -0
- data/lib/active_support/core_ext/kernel/reporting.rb +9 -78
- data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
- data/lib/active_support/core_ext/kernel.rb +5 -4
- data/lib/active_support/core_ext/load_error.rb +5 -21
- data/lib/active_support/core_ext/module/aliasing.rb +6 -44
- data/lib/active_support/core_ext/module/anonymous.rb +12 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +8 -8
- data/lib/active_support/core_ext/module/attribute_accessors.rb +186 -44
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +157 -0
- data/lib/active_support/core_ext/module/concerning.rb +140 -0
- data/lib/active_support/core_ext/module/delegation.rb +172 -45
- data/lib/active_support/core_ext/module/deprecation.rb +3 -3
- data/lib/active_support/core_ext/module/introspection.rb +23 -38
- data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
- data/lib/active_support/core_ext/module/remove_method.rb +8 -3
- data/lib/active_support/core_ext/module.rb +13 -10
- data/lib/active_support/core_ext/name_error.rb +45 -4
- data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +135 -127
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
- data/lib/active_support/core_ext/numeric/time.rb +37 -50
- data/lib/active_support/core_ext/numeric.rb +6 -3
- data/lib/active_support/core_ext/object/acts_like.rb +41 -6
- data/lib/active_support/core_ext/object/blank.rb +70 -20
- data/lib/active_support/core_ext/object/conversions.rb +6 -4
- data/lib/active_support/core_ext/object/deep_dup.rb +19 -10
- data/lib/active_support/core_ext/object/duplicable.rb +17 -47
- data/lib/active_support/core_ext/object/inclusion.rb +18 -15
- data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
- data/lib/active_support/core_ext/object/json.rb +244 -0
- data/lib/active_support/core_ext/object/to_param.rb +3 -1
- data/lib/active_support/core_ext/object/to_query.rb +21 -8
- data/lib/active_support/core_ext/object/try.rb +106 -26
- data/lib/active_support/core_ext/object/with_options.rb +64 -5
- data/lib/active_support/core_ext/object.rb +14 -12
- data/lib/active_support/core_ext/pathname/existence.rb +21 -0
- data/lib/active_support/core_ext/pathname.rb +3 -0
- data/lib/active_support/core_ext/range/compare_range.rb +57 -0
- data/lib/active_support/core_ext/range/conversions.rb +37 -15
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/range/each.rb +18 -17
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +7 -0
- data/lib/active_support/core_ext/range/overlaps.rb +2 -0
- data/lib/active_support/core_ext/range.rb +7 -4
- data/lib/active_support/core_ext/regexp.rb +10 -1
- data/lib/active_support/core_ext/securerandom.rb +45 -0
- data/lib/active_support/core_ext/string/access.rb +42 -51
- data/lib/active_support/core_ext/string/behavior.rb +3 -1
- data/lib/active_support/core_ext/string/conversions.rb +18 -13
- data/lib/active_support/core_ext/string/exclude.rb +5 -3
- data/lib/active_support/core_ext/string/filters.rb +97 -7
- data/lib/active_support/core_ext/string/indent.rb +6 -4
- data/lib/active_support/core_ext/string/inflections.rb +106 -25
- data/lib/active_support/core_ext/string/inquiry.rb +4 -1
- data/lib/active_support/core_ext/string/multibyte.rb +18 -9
- data/lib/active_support/core_ext/string/output_safety.rb +227 -54
- data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
- data/lib/active_support/core_ext/string/strip.rb +6 -5
- data/lib/active_support/core_ext/string/zones.rb +4 -1
- data/lib/active_support/core_ext/string.rb +15 -13
- 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/time/acts_like.rb +3 -1
- data/lib/active_support/core_ext/time/calculations.rb +178 -116
- data/lib/active_support/core_ext/time/compatibility.rb +16 -0
- data/lib/active_support/core_ext/time/conversions.rb +37 -25
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/time/zones.rb +44 -42
- data/lib/active_support/core_ext/time.rb +8 -5
- data/lib/active_support/core_ext/uri.rb +4 -25
- data/lib/active_support/core_ext.rb +4 -2
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +226 -0
- data/lib/active_support/dependencies/autoload.rb +3 -1
- data/lib/active_support/dependencies/interlock.rb +49 -0
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +71 -696
- data/lib/active_support/deprecation/behaviors.rb +65 -16
- data/lib/active_support/deprecation/constant_accessor.rb +52 -0
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +16 -2
- data/lib/active_support/deprecation/method_wrappers.rb +62 -21
- data/lib/active_support/deprecation/proxy_wrappers.rb +82 -31
- data/lib/active_support/deprecation/reporting.rb +81 -18
- data/lib/active_support/deprecation.rb +19 -11
- data/lib/active_support/descendants_tracker.rb +192 -34
- 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 +67 -0
- data/lib/active_support/duration.rb +437 -39
- data/lib/active_support/encrypted_configuration.rb +56 -0
- data/lib/active_support/encrypted_file.rb +117 -0
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/error_reporter.rb +117 -0
- data/lib/active_support/evented_file_update_checker.rb +170 -0
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +53 -0
- data/lib/active_support/execution_wrapper.rb +151 -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 +62 -37
- data/lib/active_support/fork_tracker.rb +71 -0
- data/lib/active_support/gem_version.rb +17 -0
- data/lib/active_support/gzip.rb +7 -5
- data/lib/active_support/hash_with_indifferent_access.rb +207 -54
- data/lib/active_support/html_safe_translation.rb +43 -0
- data/lib/active_support/i18n.rb +10 -6
- data/lib/active_support/i18n_railtie.rb +48 -19
- data/lib/active_support/inflections.rb +19 -12
- data/lib/active_support/inflector/inflections.rb +97 -37
- data/lib/active_support/inflector/methods.rb +192 -157
- data/lib/active_support/inflector/transliterate.rb +83 -33
- data/lib/active_support/inflector.rb +7 -5
- data/lib/active_support/isolated_execution_state.rb +64 -0
- data/lib/active_support/json/decoding.rb +37 -42
- data/lib/active_support/json/encoding.rb +93 -293
- data/lib/active_support/json.rb +4 -2
- data/lib/active_support/key_generator.rb +30 -47
- data/lib/active_support/lazy_load_hooks.rb +54 -21
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +10 -4
- data/lib/active_support/log_subscriber/test_helper.rb +14 -12
- data/lib/active_support/log_subscriber.rb +61 -18
- data/lib/active_support/logger.rb +40 -4
- data/lib/active_support/logger_silence.rb +17 -20
- data/lib/active_support/logger_thread_safe_level.rb +69 -0
- data/lib/active_support/message_encryptor.rb +178 -55
- data/lib/active_support/message_verifier.rb +195 -26
- data/lib/active_support/messages/metadata.rb +80 -0
- data/lib/active_support/messages/rotation_configuration.rb +23 -0
- data/lib/active_support/messages/rotator.rb +57 -0
- data/lib/active_support/multibyte/chars.rb +45 -92
- data/lib/active_support/multibyte/unicode.rb +44 -377
- data/lib/active_support/multibyte.rb +5 -3
- data/lib/active_support/notifications/fanout.rb +177 -44
- data/lib/active_support/notifications/instrumenter.rb +117 -17
- data/lib/active_support/notifications.rb +106 -39
- data/lib/active_support/number_helper/number_converter.rb +181 -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 +59 -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 +152 -394
- data/lib/active_support/option_merger.rb +18 -5
- data/lib/active_support/ordered_hash.rb +8 -6
- data/lib/active_support/ordered_options.rb +43 -7
- data/lib/active_support/parameter_filter.rb +138 -0
- data/lib/active_support/per_thread_registry.rb +24 -11
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/rails.rb +10 -11
- data/lib/active_support/railtie.rb +118 -12
- data/lib/active_support/reloader.rb +130 -0
- data/lib/active_support/rescuable.rb +112 -57
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +38 -0
- data/lib/active_support/string_inquirer.rb +11 -4
- data/lib/active_support/subscriber.rb +109 -39
- data/lib/active_support/tagged_logging.rb +54 -17
- data/lib/active_support/test_case.rb +121 -37
- data/lib/active_support/testing/assertions.rb +177 -39
- data/lib/active_support/testing/autorun.rb +5 -3
- data/lib/active_support/testing/constant_lookup.rb +3 -6
- data/lib/active_support/testing/declarative.rb +10 -22
- data/lib/active_support/testing/deprecation.rb +65 -11
- data/lib/active_support/testing/file_fixtures.rb +38 -0
- data/lib/active_support/testing/isolation.rb +56 -87
- data/lib/active_support/testing/method_call_assertions.rb +70 -0
- data/lib/active_support/testing/parallelization/server.rb +82 -0
- data/lib/active_support/testing/parallelization/worker.rb +103 -0
- data/lib/active_support/testing/parallelization.rb +55 -0
- data/lib/active_support/testing/parallelize_executor.rb +76 -0
- data/lib/active_support/testing/setup_and_teardown.rb +30 -10
- data/lib/active_support/testing/stream.rb +41 -0
- data/lib/active_support/testing/tagged_logging.rb +6 -4
- data/lib/active_support/testing/time_helpers.rb +246 -0
- data/lib/active_support/time.rb +13 -13
- data/lib/active_support/time_with_zone.rb +315 -90
- data/lib/active_support/values/time_zone.rb +306 -135
- data/lib/active_support/version.rb +6 -7
- data/lib/active_support/xml_mini/jdom.rb +117 -115
- data/lib/active_support/xml_mini/libxml.rb +22 -21
- data/lib/active_support/xml_mini/libxmlsax.rb +17 -19
- data/lib/active_support/xml_mini/nokogiri.rb +19 -19
- data/lib/active_support/xml_mini/nokogirisax.rb +16 -17
- data/lib/active_support/xml_mini/rexml.rb +25 -17
- data/lib/active_support/xml_mini.rb +67 -56
- data/lib/active_support.rb +58 -3
- metadata +125 -66
- data/lib/active_support/basic_object.rb +0 -11
- data/lib/active_support/buffered_logger.rb +0 -21
- data/lib/active_support/concurrency/latch.rb +0 -27
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
- data/lib/active_support/core_ext/array/uniq_by.rb +0 -19
- data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -40
- data/lib/active_support/core_ext/date_time/zones.rb +0 -24
- data/lib/active_support/core_ext/hash/diff.rb +0 -14
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
- data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
- data/lib/active_support/core_ext/logger.rb +0 -67
- data/lib/active_support/core_ext/marshal.rb +0 -21
- data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
- data/lib/active_support/core_ext/module/reachable.rb +0 -8
- data/lib/active_support/core_ext/object/to_json.rb +0 -27
- data/lib/active_support/core_ext/proc.rb +0 -17
- data/lib/active_support/core_ext/range/include_range.rb +0 -23
- data/lib/active_support/core_ext/string/encoding.rb +0 -8
- data/lib/active_support/core_ext/struct.rb +0 -6
- data/lib/active_support/core_ext/thread.rb +0 -79
- data/lib/active_support/core_ext/time/marshal.rb +0 -30
- data/lib/active_support/file_watcher.rb +0 -36
- data/lib/active_support/json/variable.rb +0 -18
- data/lib/active_support/testing/pending.rb +0 -14
- data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,7 +1,7 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "active_support/inflections"
|
4
|
+
require "active_support/core_ext/object/blank"
|
5
5
|
|
6
6
|
module ActiveSupport
|
7
7
|
# The Inflector transforms words from singular to plural, class names to table
|
@@ -23,153 +23,212 @@ module ActiveSupport
|
|
23
23
|
# pluralized using rules defined for that language. By default,
|
24
24
|
# this parameter is set to <tt>:en</tt>.
|
25
25
|
#
|
26
|
-
# 'post'
|
27
|
-
# 'octopus'
|
28
|
-
# 'sheep'
|
29
|
-
# 'words'
|
30
|
-
# 'CamelOctopus'
|
31
|
-
# 'ley'
|
26
|
+
# pluralize('post') # => "posts"
|
27
|
+
# pluralize('octopus') # => "octopi"
|
28
|
+
# pluralize('sheep') # => "sheep"
|
29
|
+
# pluralize('words') # => "words"
|
30
|
+
# pluralize('CamelOctopus') # => "CamelOctopi"
|
31
|
+
# pluralize('ley', :es) # => "leyes"
|
32
32
|
def pluralize(word, locale = :en)
|
33
|
-
apply_inflections(word, inflections(locale).plurals)
|
33
|
+
apply_inflections(word, inflections(locale).plurals, locale)
|
34
34
|
end
|
35
35
|
|
36
|
-
# The reverse of
|
36
|
+
# The reverse of #pluralize, returns the singular form of a word in a
|
37
37
|
# string.
|
38
38
|
#
|
39
39
|
# If passed an optional +locale+ parameter, the word will be
|
40
|
-
#
|
40
|
+
# singularized using rules defined for that language. By default,
|
41
41
|
# this parameter is set to <tt>:en</tt>.
|
42
42
|
#
|
43
|
-
# 'posts'
|
44
|
-
# 'octopi'
|
45
|
-
# 'sheep'
|
46
|
-
# 'word'
|
47
|
-
# 'CamelOctopi'
|
48
|
-
# 'leyes'
|
43
|
+
# singularize('posts') # => "post"
|
44
|
+
# singularize('octopi') # => "octopus"
|
45
|
+
# singularize('sheep') # => "sheep"
|
46
|
+
# singularize('word') # => "word"
|
47
|
+
# singularize('CamelOctopi') # => "CamelOctopus"
|
48
|
+
# singularize('leyes', :es) # => "ley"
|
49
49
|
def singularize(word, locale = :en)
|
50
|
-
apply_inflections(word, inflections(locale).singulars)
|
50
|
+
apply_inflections(word, inflections(locale).singulars, locale)
|
51
51
|
end
|
52
52
|
|
53
|
-
#
|
54
|
-
#
|
53
|
+
# Converts strings to UpperCamelCase.
|
54
|
+
# If the +uppercase_first_letter+ parameter is set to false, then produces
|
55
55
|
# lowerCamelCase.
|
56
56
|
#
|
57
|
-
#
|
57
|
+
# Also converts '/' to '::' which is useful for converting
|
58
58
|
# paths to namespaces.
|
59
59
|
#
|
60
|
-
# 'active_model'
|
61
|
-
# 'active_model'
|
62
|
-
# 'active_model/errors'
|
63
|
-
# 'active_model/errors'
|
60
|
+
# camelize('active_model') # => "ActiveModel"
|
61
|
+
# camelize('active_model', false) # => "activeModel"
|
62
|
+
# camelize('active_model/errors') # => "ActiveModel::Errors"
|
63
|
+
# camelize('active_model/errors', false) # => "activeModel::Errors"
|
64
64
|
#
|
65
65
|
# As a rule of thumb you can think of +camelize+ as the inverse of
|
66
|
-
#
|
66
|
+
# #underscore, though there are cases where that does not hold:
|
67
67
|
#
|
68
|
-
# 'SSLError'
|
68
|
+
# camelize(underscore('SSLError')) # => "SslError"
|
69
69
|
def camelize(term, uppercase_first_letter = true)
|
70
70
|
string = term.to_s
|
71
|
-
|
72
|
-
|
71
|
+
# String#camelize takes a symbol (:upper or :lower), so here we also support :lower to keep the methods consistent.
|
72
|
+
if !uppercase_first_letter || uppercase_first_letter == :lower
|
73
|
+
string = string.sub(inflections.acronyms_camelize_regex) { |match| match.downcase! || match }
|
73
74
|
else
|
74
|
-
string = string.sub(/^
|
75
|
+
string = string.sub(/^[a-z\d]*/) { |match| inflections.acronyms[match] || match.capitalize! || match }
|
76
|
+
end
|
77
|
+
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) do
|
78
|
+
word = $2
|
79
|
+
substituted = inflections.acronyms[word] || word.capitalize! || word
|
80
|
+
$1 ? "::#{substituted}" : substituted
|
75
81
|
end
|
76
|
-
string
|
82
|
+
string
|
77
83
|
end
|
78
84
|
|
79
85
|
# Makes an underscored, lowercase form from the expression in the string.
|
80
86
|
#
|
81
87
|
# Changes '::' to '/' to convert namespaces to paths.
|
82
88
|
#
|
83
|
-
# 'ActiveModel'
|
84
|
-
# 'ActiveModel::Errors'
|
89
|
+
# underscore('ActiveModel') # => "active_model"
|
90
|
+
# underscore('ActiveModel::Errors') # => "active_model/errors"
|
85
91
|
#
|
86
92
|
# As a rule of thumb you can think of +underscore+ as the inverse of
|
87
|
-
#
|
93
|
+
# #camelize, though there are cases where that does not hold:
|
88
94
|
#
|
89
|
-
# 'SSLError'
|
95
|
+
# camelize(underscore('SSLError')) # => "SslError"
|
90
96
|
def underscore(camel_cased_word)
|
91
|
-
|
92
|
-
word.gsub
|
93
|
-
word.gsub!(
|
94
|
-
word.gsub!(/([A-Z
|
95
|
-
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
97
|
+
return camel_cased_word.to_s unless /[A-Z-]|::/.match?(camel_cased_word)
|
98
|
+
word = camel_cased_word.to_s.gsub("::", "/")
|
99
|
+
word.gsub!(inflections.acronyms_underscore_regex) { "#{$1 && '_' }#{$2.downcase}" }
|
100
|
+
word.gsub!(/([A-Z]+)(?=[A-Z][a-z])|([a-z\d])(?=[A-Z])/) { ($1 || $2) << "_" }
|
96
101
|
word.tr!("-", "_")
|
97
102
|
word.downcase!
|
98
103
|
word
|
99
104
|
end
|
100
105
|
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
106
|
+
# Tweaks an attribute name for display to end users.
|
107
|
+
#
|
108
|
+
# Specifically, performs these transformations:
|
109
|
+
#
|
110
|
+
# * Applies human inflection rules to the argument.
|
111
|
+
# * Deletes leading underscores, if any.
|
112
|
+
# * Removes an "_id" suffix if present.
|
113
|
+
# * Replaces underscores with spaces, if any.
|
114
|
+
# * Downcases all words except acronyms.
|
115
|
+
# * Capitalizes the first word.
|
116
|
+
# The capitalization of the first word can be turned off by setting the
|
117
|
+
# +:capitalize+ option to false (default is true).
|
118
|
+
#
|
119
|
+
# The trailing '_id' can be kept and capitalized by setting the
|
120
|
+
# optional parameter +keep_id_suffix+ to true (default is false).
|
104
121
|
#
|
105
|
-
# 'employee_salary'
|
106
|
-
# 'author_id'
|
107
|
-
|
122
|
+
# humanize('employee_salary') # => "Employee salary"
|
123
|
+
# humanize('author_id') # => "Author"
|
124
|
+
# humanize('author_id', capitalize: false) # => "author"
|
125
|
+
# humanize('_id') # => "Id"
|
126
|
+
# humanize('author_id', keep_id_suffix: true) # => "Author id"
|
127
|
+
#
|
128
|
+
# If "SSL" was defined to be an acronym:
|
129
|
+
#
|
130
|
+
# humanize('ssl_error') # => "SSL error"
|
131
|
+
#
|
132
|
+
def humanize(lower_case_and_underscored_word, capitalize: true, keep_id_suffix: false)
|
108
133
|
result = lower_case_and_underscored_word.to_s.dup
|
134
|
+
|
109
135
|
inflections.humans.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
|
110
|
-
|
111
|
-
result.tr!(
|
112
|
-
result.
|
113
|
-
|
114
|
-
|
136
|
+
|
137
|
+
result.tr!("_", " ")
|
138
|
+
result.lstrip!
|
139
|
+
unless keep_id_suffix
|
140
|
+
result.delete_suffix!(" id")
|
141
|
+
end
|
142
|
+
|
143
|
+
result.gsub!(/([a-z\d]+)/i) do |match|
|
144
|
+
match.downcase!
|
145
|
+
inflections.acronyms[match] || match
|
146
|
+
end
|
147
|
+
|
148
|
+
if capitalize
|
149
|
+
result.sub!(/\A\w/) do |match|
|
150
|
+
match.upcase!
|
151
|
+
match
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
result
|
156
|
+
end
|
157
|
+
|
158
|
+
# Converts just the first character to uppercase.
|
159
|
+
#
|
160
|
+
# upcase_first('what a Lovely Day') # => "What a Lovely Day"
|
161
|
+
# upcase_first('w') # => "W"
|
162
|
+
# upcase_first('') # => ""
|
163
|
+
def upcase_first(string)
|
164
|
+
string.length > 0 ? string[0].upcase.concat(string[1..-1]) : ""
|
115
165
|
end
|
116
166
|
|
117
167
|
# Capitalizes all the words and replaces some characters in the string to
|
118
168
|
# create a nicer looking title. +titleize+ is meant for creating pretty
|
119
169
|
# output. It is not used in the Rails internals.
|
120
170
|
#
|
171
|
+
# The trailing '_id','Id'.. can be kept and capitalized by setting the
|
172
|
+
# optional parameter +keep_id_suffix+ to true.
|
173
|
+
# By default, this parameter is false.
|
174
|
+
#
|
121
175
|
# +titleize+ is also aliased as +titlecase+.
|
122
176
|
#
|
123
|
-
# 'man from the boondocks'
|
124
|
-
# 'x-men: the last stand'
|
125
|
-
# 'TheManWithoutAPast'
|
126
|
-
# 'raiders_of_the_lost_ark'
|
127
|
-
|
128
|
-
|
177
|
+
# titleize('man from the boondocks') # => "Man From The Boondocks"
|
178
|
+
# titleize('x-men: the last stand') # => "X Men: The Last Stand"
|
179
|
+
# titleize('TheManWithoutAPast') # => "The Man Without A Past"
|
180
|
+
# titleize('raiders_of_the_lost_ark') # => "Raiders Of The Lost Ark"
|
181
|
+
# titleize('string_ending_with_id', keep_id_suffix: true) # => "String Ending With Id"
|
182
|
+
def titleize(word, keep_id_suffix: false)
|
183
|
+
humanize(underscore(word), keep_id_suffix: keep_id_suffix).gsub(/\b(?<!\w['’`()])[a-z]/) do |match|
|
184
|
+
match.capitalize
|
185
|
+
end
|
129
186
|
end
|
130
187
|
|
131
|
-
#
|
132
|
-
# method uses the
|
188
|
+
# Creates the name of a table like Rails does for models to table names.
|
189
|
+
# This method uses the #pluralize method on the last word in the string.
|
133
190
|
#
|
134
|
-
# 'RawScaledScorer'
|
135
|
-
# '
|
136
|
-
# 'fancyCategory'
|
191
|
+
# tableize('RawScaledScorer') # => "raw_scaled_scorers"
|
192
|
+
# tableize('ham_and_egg') # => "ham_and_eggs"
|
193
|
+
# tableize('fancyCategory') # => "fancy_categories"
|
137
194
|
def tableize(class_name)
|
138
195
|
pluralize(underscore(class_name))
|
139
196
|
end
|
140
197
|
|
141
|
-
#
|
198
|
+
# Creates a class name from a plural table name like Rails does for table
|
142
199
|
# names to models. Note that this returns a string and not a Class (To
|
143
|
-
# convert to an actual class follow +classify+ with
|
200
|
+
# convert to an actual class follow +classify+ with #constantize).
|
144
201
|
#
|
145
|
-
# '
|
146
|
-
# 'posts'
|
202
|
+
# classify('ham_and_eggs') # => "HamAndEgg"
|
203
|
+
# classify('posts') # => "Post"
|
147
204
|
#
|
148
205
|
# Singular names are not handled correctly:
|
149
206
|
#
|
150
|
-
# '
|
207
|
+
# classify('calculus') # => "Calculu"
|
151
208
|
def classify(table_name)
|
152
209
|
# strip out any leading schema name
|
153
|
-
camelize(singularize(table_name.to_s.sub(/.*\./,
|
210
|
+
camelize(singularize(table_name.to_s.sub(/.*\./, "")))
|
154
211
|
end
|
155
212
|
|
156
213
|
# Replaces underscores with dashes in the string.
|
157
214
|
#
|
158
|
-
# 'puni_puni'
|
215
|
+
# dasherize('puni_puni') # => "puni-puni"
|
159
216
|
def dasherize(underscored_word)
|
160
|
-
underscored_word.tr(
|
217
|
+
underscored_word.tr("_", "-")
|
161
218
|
end
|
162
219
|
|
163
220
|
# Removes the module part from the expression in the string.
|
164
221
|
#
|
165
|
-
# '
|
166
|
-
# 'Inflections'
|
222
|
+
# demodulize('ActiveSupport::Inflector::Inflections') # => "Inflections"
|
223
|
+
# demodulize('Inflections') # => "Inflections"
|
224
|
+
# demodulize('::Inflections') # => "Inflections"
|
225
|
+
# demodulize('') # => ""
|
167
226
|
#
|
168
|
-
# See also
|
227
|
+
# See also #deconstantize.
|
169
228
|
def demodulize(path)
|
170
229
|
path = path.to_s
|
171
|
-
if i = path.rindex(
|
172
|
-
path[(i+2)..-1]
|
230
|
+
if i = path.rindex("::")
|
231
|
+
path[(i + 2)..-1]
|
173
232
|
else
|
174
233
|
path
|
175
234
|
end
|
@@ -177,32 +236,32 @@ module ActiveSupport
|
|
177
236
|
|
178
237
|
# Removes the rightmost segment from the constant expression in the string.
|
179
238
|
#
|
180
|
-
# 'Net::HTTP'
|
181
|
-
# '::Net::HTTP'
|
182
|
-
# 'String'
|
183
|
-
# '::String'
|
184
|
-
# ''
|
239
|
+
# deconstantize('Net::HTTP') # => "Net"
|
240
|
+
# deconstantize('::Net::HTTP') # => "::Net"
|
241
|
+
# deconstantize('String') # => ""
|
242
|
+
# deconstantize('::String') # => ""
|
243
|
+
# deconstantize('') # => ""
|
185
244
|
#
|
186
|
-
# See also
|
245
|
+
# See also #demodulize.
|
187
246
|
def deconstantize(path)
|
188
|
-
path.to_s[0
|
247
|
+
path.to_s[0, path.rindex("::") || 0] # implementation based on the one in facets' Module#spacename
|
189
248
|
end
|
190
249
|
|
191
250
|
# Creates a foreign key name from a class name.
|
192
251
|
# +separate_class_name_and_id_with_underscore+ sets whether
|
193
252
|
# the method should put '_' between the name and 'id'.
|
194
253
|
#
|
195
|
-
# 'Message'
|
196
|
-
# 'Message'
|
197
|
-
# 'Admin::Post'
|
254
|
+
# foreign_key('Message') # => "message_id"
|
255
|
+
# foreign_key('Message', false) # => "messageid"
|
256
|
+
# foreign_key('Admin::Post') # => "post_id"
|
198
257
|
def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
|
199
258
|
underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id")
|
200
259
|
end
|
201
260
|
|
202
261
|
# Tries to find a constant with the name specified in the argument string.
|
203
262
|
#
|
204
|
-
# 'Module'
|
205
|
-
# '
|
263
|
+
# constantize('Module') # => Module
|
264
|
+
# constantize('Foo::Bar') # => Foo::Bar
|
206
265
|
#
|
207
266
|
# The name is assumed to be the one of a top-level constant, no matter
|
208
267
|
# whether it starts with "::" or not. No lexical context is taken into
|
@@ -211,42 +270,20 @@ module ActiveSupport
|
|
211
270
|
# C = 'outside'
|
212
271
|
# module M
|
213
272
|
# C = 'inside'
|
214
|
-
# C
|
215
|
-
# 'C'
|
273
|
+
# C # => 'inside'
|
274
|
+
# constantize('C') # => 'outside', same as ::C
|
216
275
|
# end
|
217
276
|
#
|
218
277
|
# NameError is raised when the name is not in CamelCase or the constant is
|
219
278
|
# unknown.
|
220
279
|
def constantize(camel_cased_word)
|
221
|
-
|
222
|
-
names.shift if names.empty? || names.first.empty?
|
223
|
-
|
224
|
-
names.inject(Object) do |constant, name|
|
225
|
-
if constant == Object
|
226
|
-
constant.const_get(name)
|
227
|
-
else
|
228
|
-
candidate = constant.const_get(name)
|
229
|
-
next candidate if constant.const_defined?(name, false)
|
230
|
-
next candidate unless Object.const_defined?(name)
|
231
|
-
|
232
|
-
# Go down the ancestors to check it it's owned
|
233
|
-
# directly before we reach Object or the end of ancestors.
|
234
|
-
constant = constant.ancestors.inject do |const, ancestor|
|
235
|
-
break const if ancestor == Object
|
236
|
-
break ancestor if ancestor.const_defined?(name, false)
|
237
|
-
const
|
238
|
-
end
|
239
|
-
|
240
|
-
# owner is in Object, so raise
|
241
|
-
constant.const_get(name, false)
|
242
|
-
end
|
243
|
-
end
|
280
|
+
Object.const_get(camel_cased_word)
|
244
281
|
end
|
245
282
|
|
246
283
|
# Tries to find a constant with the name specified in the argument string.
|
247
284
|
#
|
248
|
-
# 'Module'
|
249
|
-
# '
|
285
|
+
# safe_constantize('Module') # => Module
|
286
|
+
# safe_constantize('Foo::Bar') # => Foo::Bar
|
250
287
|
#
|
251
288
|
# The name is assumed to be the one of a top-level constant, no matter
|
252
289
|
# whether it starts with "::" or not. No lexical context is taken into
|
@@ -255,23 +292,24 @@ module ActiveSupport
|
|
255
292
|
# C = 'outside'
|
256
293
|
# module M
|
257
294
|
# C = 'inside'
|
258
|
-
# C
|
259
|
-
# 'C'
|
295
|
+
# C # => 'inside'
|
296
|
+
# safe_constantize('C') # => 'outside', same as ::C
|
260
297
|
# end
|
261
298
|
#
|
262
299
|
# +nil+ is returned when the name is not in CamelCase or the constant (or
|
263
300
|
# part of it) is unknown.
|
264
301
|
#
|
265
|
-
# 'blargle'
|
266
|
-
# 'UnknownModule'
|
267
|
-
# 'UnknownModule::Foo::Bar'
|
302
|
+
# safe_constantize('blargle') # => nil
|
303
|
+
# safe_constantize('UnknownModule') # => nil
|
304
|
+
# safe_constantize('UnknownModule::Foo::Bar') # => nil
|
268
305
|
def safe_constantize(camel_cased_word)
|
269
306
|
constantize(camel_cased_word)
|
270
307
|
rescue NameError => e
|
271
|
-
raise
|
272
|
-
e.name.to_s == camel_cased_word.to_s
|
273
|
-
rescue
|
274
|
-
|
308
|
+
raise if e.name && !(camel_cased_word.to_s.split("::").include?(e.name.to_s) ||
|
309
|
+
e.name.to_s == camel_cased_word.to_s)
|
310
|
+
rescue LoadError => e
|
311
|
+
message = e.respond_to?(:original_message) ? e.original_message : e.message
|
312
|
+
raise unless /Unable to autoload constant #{const_regexp(camel_cased_word)}/.match?(message)
|
275
313
|
end
|
276
314
|
|
277
315
|
# Returns the suffix that should be added to a number to denote the position
|
@@ -284,18 +322,7 @@ module ActiveSupport
|
|
284
322
|
# ordinal(-11) # => "th"
|
285
323
|
# ordinal(-1021) # => "st"
|
286
324
|
def ordinal(number)
|
287
|
-
|
288
|
-
|
289
|
-
if (11..13).include?(abs_number % 100)
|
290
|
-
"th"
|
291
|
-
else
|
292
|
-
case abs_number % 10
|
293
|
-
when 1; "st"
|
294
|
-
when 2; "nd"
|
295
|
-
when 3; "rd"
|
296
|
-
else "th"
|
297
|
-
end
|
298
|
-
end
|
325
|
+
I18n.translate("number.nth.ordinals", number: number)
|
299
326
|
end
|
300
327
|
|
301
328
|
# Turns a number into an ordinal string used to denote the position in an
|
@@ -308,35 +335,43 @@ module ActiveSupport
|
|
308
335
|
# ordinalize(-11) # => "-11th"
|
309
336
|
# ordinalize(-1021) # => "-1021st"
|
310
337
|
def ordinalize(number)
|
311
|
-
"
|
338
|
+
I18n.translate("number.nth.ordinalized", number: number)
|
312
339
|
end
|
313
340
|
|
314
341
|
private
|
342
|
+
# Mounts a regular expression, returned as a string to ease interpolation,
|
343
|
+
# that will match part by part the given constant.
|
344
|
+
#
|
345
|
+
# const_regexp("Foo::Bar::Baz") # => "Foo(::Bar(::Baz)?)?"
|
346
|
+
# const_regexp("::") # => "::"
|
347
|
+
def const_regexp(camel_cased_word)
|
348
|
+
parts = camel_cased_word.split("::")
|
349
|
+
|
350
|
+
return Regexp.escape(camel_cased_word) if parts.blank?
|
315
351
|
|
316
|
-
|
317
|
-
# For instance, Foo::Bar::Baz will generate Foo(::Bar(::Baz)?)?
|
318
|
-
def const_regexp(camel_cased_word) #:nodoc:
|
319
|
-
parts = camel_cased_word.split("::")
|
320
|
-
last = parts.pop
|
352
|
+
last = parts.pop
|
321
353
|
|
322
|
-
|
323
|
-
|
354
|
+
parts.reverse!.inject(last) do |acc, part|
|
355
|
+
part.empty? ? acc : "#{part}(::#{acc})?"
|
356
|
+
end
|
324
357
|
end
|
325
|
-
end
|
326
358
|
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
359
|
+
# Applies inflection rules for +singularize+ and +pluralize+.
|
360
|
+
#
|
361
|
+
# If passed an optional +locale+ parameter, the uncountables will be
|
362
|
+
# found for that locale.
|
363
|
+
#
|
364
|
+
# apply_inflections('post', inflections.plurals, :en) # => "posts"
|
365
|
+
# apply_inflections('posts', inflections.singulars, :en) # => "post"
|
366
|
+
def apply_inflections(word, rules, locale = :en)
|
367
|
+
result = word.to_s.dup
|
333
368
|
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
369
|
+
if word.empty? || inflections(locale).uncountables.uncountable?(result)
|
370
|
+
result
|
371
|
+
else
|
372
|
+
rules.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
|
373
|
+
result
|
374
|
+
end
|
339
375
|
end
|
340
|
-
end
|
341
376
|
end
|
342
377
|
end
|
@@ -1,9 +1,11 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/string/multibyte"
|
4
|
+
require "active_support/i18n"
|
4
5
|
|
5
6
|
module ActiveSupport
|
6
7
|
module Inflector
|
8
|
+
ALLOWED_ENCODINGS_FOR_TRANSLITERATE = [Encoding::UTF_8, Encoding::US_ASCII, Encoding::GB18030].freeze
|
7
9
|
|
8
10
|
# Replaces non-ASCII characters with an ASCII approximation, or if none
|
9
11
|
# exists, a replacement character which defaults to "?".
|
@@ -51,47 +53,95 @@ module ActiveSupport
|
|
51
53
|
#
|
52
54
|
# Now you can have different transliterations for each locale:
|
53
55
|
#
|
54
|
-
#
|
55
|
-
# transliterate('Jürgen')
|
56
|
+
# transliterate('Jürgen', locale: :en)
|
56
57
|
# # => "Jurgen"
|
57
58
|
#
|
58
|
-
#
|
59
|
-
# transliterate('Jürgen')
|
59
|
+
# transliterate('Jürgen', locale: :de)
|
60
60
|
# # => "Juergen"
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
61
|
+
#
|
62
|
+
# Transliteration is restricted to UTF-8, US-ASCII and GB18030 strings
|
63
|
+
# Other encodings will raise an ArgumentError.
|
64
|
+
def transliterate(string, replacement = "?", locale: nil)
|
65
|
+
string = string.dup if string.frozen?
|
66
|
+
raise ArgumentError, "Can only transliterate strings. Received #{string.class.name}" unless string.is_a?(String)
|
67
|
+
raise ArgumentError, "Cannot transliterate strings with #{string.encoding} encoding" unless ALLOWED_ENCODINGS_FOR_TRANSLITERATE.include?(string.encoding)
|
68
|
+
|
69
|
+
input_encoding = string.encoding
|
70
|
+
|
71
|
+
# US-ASCII is a subset of UTF-8 so we'll force encoding as UTF-8 if
|
72
|
+
# US-ASCII is given. This way we can let tidy_bytes handle the string
|
73
|
+
# in the same way as we do for UTF-8
|
74
|
+
string.force_encoding(Encoding::UTF_8) if string.encoding == Encoding::US_ASCII
|
75
|
+
|
76
|
+
# GB18030 is Unicode compatible but is not a direct mapping so needs to be
|
77
|
+
# transcoded. Using invalid/undef :replace will result in loss of data in
|
78
|
+
# the event of invalid characters, but since tidy_bytes will replace
|
79
|
+
# invalid/undef with a "?" we're safe to do the same beforehand
|
80
|
+
string.encode!(Encoding::UTF_8, invalid: :replace, undef: :replace) if string.encoding == Encoding::GB18030
|
81
|
+
|
82
|
+
transliterated = I18n.transliterate(
|
83
|
+
ActiveSupport::Multibyte::Unicode.tidy_bytes(string).unicode_normalize(:nfc),
|
84
|
+
replacement: replacement,
|
85
|
+
locale: locale
|
86
|
+
)
|
87
|
+
|
88
|
+
# Restore the string encoding of the input if it was not UTF-8.
|
89
|
+
# Apply invalid/undef :replace as tidy_bytes does
|
90
|
+
transliterated.encode!(input_encoding, invalid: :replace, undef: :replace) if input_encoding != transliterated.encoding
|
91
|
+
|
92
|
+
transliterated
|
65
93
|
end
|
66
94
|
|
67
95
|
# Replaces special characters in a string so that it may be used as part of
|
68
96
|
# a 'pretty' URL.
|
69
97
|
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
# # =>
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
98
|
+
# parameterize("Donald E. Knuth") # => "donald-e-knuth"
|
99
|
+
# parameterize("^très|Jolie-- ") # => "tres-jolie"
|
100
|
+
#
|
101
|
+
# To use a custom separator, override the +separator+ argument.
|
102
|
+
#
|
103
|
+
# parameterize("Donald E. Knuth", separator: '_') # => "donald_e_knuth"
|
104
|
+
# parameterize("^très|Jolie__ ", separator: '_') # => "tres_jolie"
|
105
|
+
#
|
106
|
+
# To preserve the case of the characters in a string, use the +preserve_case+ argument.
|
107
|
+
#
|
108
|
+
# parameterize("Donald E. Knuth", preserve_case: true) # => "Donald-E-Knuth"
|
109
|
+
# parameterize("^très|Jolie-- ", preserve_case: true) # => "tres-Jolie"
|
110
|
+
#
|
111
|
+
# It preserves dashes and underscores unless they are used as separators:
|
112
|
+
#
|
113
|
+
# parameterize("^très|Jolie__ ") # => "tres-jolie__"
|
114
|
+
# parameterize("^très|Jolie-- ", separator: "_") # => "tres_jolie--"
|
115
|
+
# parameterize("^très_Jolie-- ", separator: ".") # => "tres_jolie--"
|
116
|
+
#
|
117
|
+
# If the optional parameter +locale+ is specified,
|
118
|
+
# the word will be parameterized as a word of that language.
|
119
|
+
# By default, this parameter is set to <tt>nil</tt> and it will use
|
120
|
+
# the configured <tt>I18n.locale</tt>.
|
121
|
+
def parameterize(string, separator: "-", preserve_case: false, locale: nil)
|
122
|
+
# Replace accented chars with their ASCII equivalents.
|
123
|
+
parameterized_string = transliterate(string, locale: locale)
|
124
|
+
|
125
|
+
# Turn unwanted chars into the separator.
|
126
|
+
parameterized_string.gsub!(/[^a-z0-9\-_]+/i, separator)
|
127
|
+
|
128
|
+
unless separator.nil? || separator.empty?
|
129
|
+
if separator == "-"
|
130
|
+
re_duplicate_separator = /-{2,}/
|
131
|
+
re_leading_trailing_separator = /^-|-$/i
|
132
|
+
else
|
133
|
+
re_sep = Regexp.escape(separator)
|
134
|
+
re_duplicate_separator = /#{re_sep}{2,}/
|
135
|
+
re_leading_trailing_separator = /^#{re_sep}|#{re_sep}$/i
|
136
|
+
end
|
88
137
|
# No more than one of the separator in a row.
|
89
|
-
parameterized_string.gsub!(
|
138
|
+
parameterized_string.gsub!(re_duplicate_separator, separator)
|
90
139
|
# Remove leading/trailing separator.
|
91
|
-
parameterized_string.gsub!(
|
140
|
+
parameterized_string.gsub!(re_leading_trailing_separator, "")
|
92
141
|
end
|
93
|
-
parameterized_string.downcase
|
94
|
-
end
|
95
142
|
|
143
|
+
parameterized_string.downcase! unless preserve_case
|
144
|
+
parameterized_string
|
145
|
+
end
|
96
146
|
end
|
97
147
|
end
|