activesupport 4.0.13 → 5.2.5
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 +412 -444
- data/MIT-LICENSE +2 -2
- data/README.rdoc +8 -4
- data/lib/active_support/all.rb +5 -3
- data/lib/active_support/array_inquirer.rb +48 -0
- data/lib/active_support/backtrace_cleaner.rb +14 -12
- data/lib/active_support/benchmarkable.rb +6 -14
- data/lib/active_support/builder.rb +3 -1
- data/lib/active_support/cache/file_store.rb +67 -51
- data/lib/active_support/cache/mem_cache_store.rb +95 -97
- data/lib/active_support/cache/memory_store.rb +28 -30
- data/lib/active_support/cache/null_store.rb +7 -8
- data/lib/active_support/cache/redis_cache_store.rb +466 -0
- data/lib/active_support/cache/strategy/local_cache.rb +70 -56
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
- data/lib/active_support/cache.rb +331 -206
- data/lib/active_support/callbacks.rb +697 -426
- data/lib/active_support/concern.rb +32 -10
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +17 -0
- data/lib/active_support/concurrency/share_lock.rb +227 -0
- data/lib/active_support/configurable.rb +8 -5
- data/lib/active_support/core_ext/array/access.rb +39 -1
- data/lib/active_support/core_ext/array/conversions.rb +24 -35
- data/lib/active_support/core_ext/array/extract_options.rb +2 -0
- data/lib/active_support/core_ext/array/grouping.rb +23 -13
- data/lib/active_support/core_ext/array/inquiry.rb +19 -0
- data/lib/active_support/core_ext/array/prepend_and_append.rb +7 -5
- data/lib/active_support/core_ext/array/wrap.rb +7 -4
- data/lib/active_support/core_ext/array.rb +9 -7
- data/lib/active_support/core_ext/benchmark.rb +3 -1
- 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 +41 -23
- data/lib/active_support/core_ext/class/attribute_accessors.rb +5 -169
- data/lib/active_support/core_ext/class/subclasses.rb +20 -8
- 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 +21 -9
- data/lib/active_support/core_ext/date/conversions.rb +32 -22
- data/lib/active_support/core_ext/date/zones.rb +5 -34
- data/lib/active_support/core_ext/date.rb +6 -4
- data/lib/active_support/core_ext/date_and_time/calculations.rb +199 -57
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +16 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +41 -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 +78 -37
- data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +19 -13
- data/lib/active_support/core_ext/date_time.rb +7 -4
- data/lib/active_support/core_ext/digest/uuid.rb +53 -0
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +113 -29
- data/lib/active_support/core_ext/file/atomic.rb +38 -31
- data/lib/active_support/core_ext/file.rb +3 -1
- data/lib/active_support/core_ext/hash/compact.rb +29 -0
- 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/except.rb +12 -3
- data/lib/active_support/core_ext/hash/indifferent_access.rb +5 -3
- data/lib/active_support/core_ext/hash/keys.rb +50 -38
- data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
- data/lib/active_support/core_ext/hash/slice.rb +12 -6
- data/lib/active_support/core_ext/hash/transform_values.rb +32 -0
- data/lib/active_support/core_ext/hash.rb +11 -8
- data/lib/active_support/core_ext/integer/inflections.rb +3 -1
- data/lib/active_support/core_ext/integer/multiple.rb +2 -0
- 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/agnostics.rb +2 -0
- data/lib/active_support/core_ext/kernel/concern.rb +14 -0
- data/lib/active_support/core_ext/kernel/reporting.rb +5 -74
- data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
- data/lib/active_support/core_ext/kernel.rb +6 -4
- data/lib/active_support/core_ext/load_error.rb +5 -21
- data/lib/active_support/core_ext/marshal.rb +13 -10
- 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 +170 -21
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +150 -0
- data/lib/active_support/core_ext/module/concerning.rb +134 -0
- data/lib/active_support/core_ext/module/delegation.rb +135 -45
- data/lib/active_support/core_ext/module/deprecation.rb +3 -3
- data/lib/active_support/core_ext/module/introspection.rb +9 -25
- data/lib/active_support/core_ext/module/reachable.rb +5 -2
- data/lib/active_support/core_ext/module/redefine_method.rb +49 -0
- data/lib/active_support/core_ext/module/remove_method.rb +8 -3
- data/lib/active_support/core_ext/module.rb +14 -10
- data/lib/active_support/core_ext/name_error.rb +22 -2
- data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +79 -74
- data/lib/active_support/core_ext/numeric/inquiry.rb +28 -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 +12 -1
- data/lib/active_support/core_ext/object/blank.rb +70 -19
- 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 +100 -34
- 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 +227 -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 +94 -24
- data/lib/active_support/core_ext/object/with_options.rb +45 -5
- data/lib/active_support/core_ext/object.rb +14 -12
- data/lib/active_support/core_ext/range/compare_range.rb +61 -0
- data/lib/active_support/core_ext/range/conversions.rb +27 -7
- data/lib/active_support/core_ext/range/each.rb +19 -17
- data/lib/active_support/core_ext/range/include_range.rb +2 -22
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -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 +6 -0
- data/lib/active_support/core_ext/securerandom.rb +25 -0
- data/lib/active_support/core_ext/string/access.rb +41 -39
- data/lib/active_support/core_ext/string/behavior.rb +3 -1
- data/lib/active_support/core_ext/string/conversions.rb +17 -13
- data/lib/active_support/core_ext/string/exclude.rb +5 -3
- data/lib/active_support/core_ext/string/filters.rb +55 -6
- data/lib/active_support/core_ext/string/indent.rb +6 -4
- data/lib/active_support/core_ext/string/inflections.rb +66 -24
- data/lib/active_support/core_ext/string/inquiry.rb +3 -1
- data/lib/active_support/core_ext/string/multibyte.rb +15 -7
- data/lib/active_support/core_ext/string/output_safety.rb +114 -54
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -0
- data/lib/active_support/core_ext/string/strip.rb +4 -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/time/acts_like.rb +3 -1
- data/lib/active_support/core_ext/time/calculations.rb +123 -110
- data/lib/active_support/core_ext/time/compatibility.rb +16 -0
- data/lib/active_support/core_ext/time/conversions.rb +23 -14
- data/lib/active_support/core_ext/time/zones.rb +42 -26
- data/lib/active_support/core_ext/time.rb +7 -5
- data/lib/active_support/core_ext/uri.rb +6 -8
- data/lib/active_support/core_ext.rb +3 -2
- data/lib/active_support/current_attributes.rb +195 -0
- data/lib/active_support/dependencies/autoload.rb +3 -1
- data/lib/active_support/dependencies/interlock.rb +57 -0
- data/lib/active_support/dependencies.rb +196 -166
- data/lib/active_support/deprecation/behaviors.rb +48 -15
- data/lib/active_support/deprecation/constant_accessor.rb +52 -0
- data/lib/active_support/deprecation/instance_delegator.rb +17 -2
- data/lib/active_support/deprecation/method_wrappers.rb +66 -20
- data/lib/active_support/deprecation/proxy_wrappers.rb +56 -28
- data/lib/active_support/deprecation/reporting.rb +32 -12
- data/lib/active_support/deprecation.rb +14 -11
- data/lib/active_support/descendants_tracker.rb +2 -0
- data/lib/active_support/digest.rb +20 -0
- data/lib/active_support/duration/iso8601_parser.rb +125 -0
- data/lib/active_support/duration/iso8601_serializer.rb +55 -0
- data/lib/active_support/duration.rb +354 -34
- data/lib/active_support/encrypted_configuration.rb +49 -0
- data/lib/active_support/encrypted_file.rb +99 -0
- data/lib/active_support/evented_file_update_checker.rb +205 -0
- data/lib/active_support/execution_wrapper.rb +128 -0
- data/lib/active_support/executor.rb +8 -0
- data/lib/active_support/file_update_checker.rb +63 -37
- 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 +158 -35
- data/lib/active_support/i18n.rb +8 -6
- data/lib/active_support/i18n_railtie.rb +38 -20
- data/lib/active_support/inflections.rb +19 -12
- data/lib/active_support/inflector/inflections.rb +79 -30
- data/lib/active_support/inflector/methods.rb +197 -129
- data/lib/active_support/inflector/transliterate.rb +48 -27
- data/lib/active_support/inflector.rb +7 -5
- data/lib/active_support/json/decoding.rb +21 -25
- data/lib/active_support/json/encoding.rb +84 -292
- data/lib/active_support/json.rb +4 -2
- data/lib/active_support/key_generator.rb +26 -28
- data/lib/active_support/lazy_load_hooks.rb +51 -21
- data/lib/active_support/locale/en.yml +2 -0
- data/lib/active_support/log_subscriber/test_helper.rb +14 -12
- data/lib/active_support/log_subscriber.rb +13 -10
- data/lib/active_support/logger.rb +54 -3
- data/lib/active_support/logger_silence.rb +12 -7
- data/lib/active_support/logger_thread_safe_level.rb +34 -0
- data/lib/active_support/message_encryptor.rb +173 -50
- data/lib/active_support/message_verifier.rb +159 -22
- data/lib/active_support/messages/metadata.rb +71 -0
- data/lib/active_support/messages/rotation_configuration.rb +22 -0
- data/lib/active_support/messages/rotator.rb +56 -0
- data/lib/active_support/multibyte/chars.rb +38 -26
- data/lib/active_support/multibyte/unicode.rb +138 -146
- data/lib/active_support/multibyte.rb +4 -2
- data/lib/active_support/notifications/fanout.rb +23 -16
- data/lib/active_support/notifications/instrumenter.rb +29 -8
- data/lib/active_support/notifications.rb +22 -13
- data/lib/active_support/number_helper/number_converter.rb +184 -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 +29 -0
- data/lib/active_support/number_helper/number_to_human_converter.rb +68 -0
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +59 -0
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +14 -0
- data/lib/active_support/number_helper/number_to_phone_converter.rb +58 -0
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +54 -0
- data/lib/active_support/number_helper/rounding_helper.rb +66 -0
- data/lib/active_support/number_helper.rb +125 -391
- data/lib/active_support/option_merger.rb +3 -1
- data/lib/active_support/ordered_hash.rb +6 -4
- data/lib/active_support/ordered_options.rb +31 -5
- data/lib/active_support/per_thread_registry.rb +19 -11
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/rails.rb +16 -8
- data/lib/active_support/railtie.rb +43 -9
- data/lib/active_support/reloader.rb +131 -0
- data/lib/active_support/rescuable.rb +108 -53
- data/lib/active_support/security_utils.rb +31 -0
- data/lib/active_support/string_inquirer.rb +11 -3
- data/lib/active_support/subscriber.rb +54 -17
- data/lib/active_support/tagged_logging.rb +14 -11
- data/lib/active_support/test_case.rb +42 -37
- data/lib/active_support/testing/assertions.rb +126 -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 +14 -10
- data/lib/active_support/testing/file_fixtures.rb +36 -0
- data/lib/active_support/testing/isolation.rb +55 -86
- data/lib/active_support/testing/method_call_assertions.rb +43 -0
- data/lib/active_support/testing/setup_and_teardown.rb +30 -10
- data/lib/active_support/testing/stream.rb +44 -0
- data/lib/active_support/testing/tagged_logging.rb +5 -3
- data/lib/active_support/testing/time_helpers.rb +200 -0
- data/lib/active_support/time.rb +13 -13
- data/lib/active_support/time_with_zone.rb +223 -73
- data/lib/active_support/values/time_zone.rb +261 -126
- data/lib/active_support/values/unicode_tables.dat +0 -0
- data/lib/active_support/version.rb +6 -7
- data/lib/active_support/xml_mini/jdom.rb +116 -113
- data/lib/active_support/xml_mini/libxml.rb +17 -16
- data/lib/active_support/xml_mini/libxmlsax.rb +16 -18
- data/lib/active_support/xml_mini/nokogiri.rb +15 -15
- data/lib/active_support/xml_mini/nokogirisax.rb +15 -16
- data/lib/active_support/xml_mini/rexml.rb +17 -16
- data/lib/active_support/xml_mini.rb +69 -51
- data/lib/active_support.rb +29 -3
- metadata +84 -54
- 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/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/debugger.rb +0 -10
- data/lib/active_support/core_ext/logger.rb +0 -67
- data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
- 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/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
@@ -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/regexp"
|
5
5
|
|
6
6
|
module ActiveSupport
|
7
7
|
# The Inflector transforms words from singular to plural, class names to table
|
@@ -23,153 +23,205 @@ 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
71
|
if uppercase_first_letter
|
72
|
-
string = string.sub(/^[a-z\d]*/) { inflections.acronyms[
|
72
|
+
string = string.sub(/^[a-z\d]*/) { |match| inflections.acronyms[match] || match.capitalize }
|
73
73
|
else
|
74
|
-
string = string.sub(
|
74
|
+
string = string.sub(inflections.acronyms_camelize_regex) { |match| match.downcase }
|
75
75
|
end
|
76
|
-
string.gsub(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }
|
76
|
+
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }
|
77
|
+
string.gsub!("/".freeze, "::".freeze)
|
78
|
+
string
|
77
79
|
end
|
78
80
|
|
79
81
|
# Makes an underscored, lowercase form from the expression in the string.
|
80
82
|
#
|
81
83
|
# Changes '::' to '/' to convert namespaces to paths.
|
82
84
|
#
|
83
|
-
# 'ActiveModel'
|
84
|
-
# 'ActiveModel::Errors'
|
85
|
+
# underscore('ActiveModel') # => "active_model"
|
86
|
+
# underscore('ActiveModel::Errors') # => "active_model/errors"
|
85
87
|
#
|
86
88
|
# As a rule of thumb you can think of +underscore+ as the inverse of
|
87
|
-
#
|
89
|
+
# #camelize, though there are cases where that does not hold:
|
88
90
|
#
|
89
|
-
# 'SSLError'
|
91
|
+
# camelize(underscore('SSLError')) # => "SslError"
|
90
92
|
def underscore(camel_cased_word)
|
91
|
-
|
92
|
-
word.gsub
|
93
|
-
word.gsub!(
|
94
|
-
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
|
95
|
-
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
96
|
-
word.tr!("-", "_")
|
93
|
+
return camel_cased_word unless /[A-Z-]|::/.match?(camel_cased_word)
|
94
|
+
word = camel_cased_word.to_s.gsub("::".freeze, "/".freeze)
|
95
|
+
word.gsub!(inflections.acronyms_underscore_regex) { "#{$1 && '_'.freeze }#{$2.downcase}" }
|
96
|
+
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2'.freeze)
|
97
|
+
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2'.freeze)
|
98
|
+
word.tr!("-".freeze, "_".freeze)
|
97
99
|
word.downcase!
|
98
100
|
word
|
99
101
|
end
|
100
102
|
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
103
|
+
# Tweaks an attribute name for display to end users.
|
104
|
+
#
|
105
|
+
# Specifically, performs these transformations:
|
106
|
+
#
|
107
|
+
# * Applies human inflection rules to the argument.
|
108
|
+
# * Deletes leading underscores, if any.
|
109
|
+
# * Removes a "_id" suffix if present.
|
110
|
+
# * Replaces underscores with spaces, if any.
|
111
|
+
# * Downcases all words except acronyms.
|
112
|
+
# * Capitalizes the first word.
|
113
|
+
# The capitalization of the first word can be turned off by setting the
|
114
|
+
# +:capitalize+ option to false (default is true).
|
115
|
+
#
|
116
|
+
# The trailing '_id' can be kept and capitalized by setting the
|
117
|
+
# optional parameter +keep_id_suffix+ to true (default is false).
|
104
118
|
#
|
105
|
-
# 'employee_salary'
|
106
|
-
# 'author_id'
|
107
|
-
|
119
|
+
# humanize('employee_salary') # => "Employee salary"
|
120
|
+
# humanize('author_id') # => "Author"
|
121
|
+
# humanize('author_id', capitalize: false) # => "author"
|
122
|
+
# humanize('_id') # => "Id"
|
123
|
+
# humanize('author_id', keep_id_suffix: true) # => "Author Id"
|
124
|
+
#
|
125
|
+
# If "SSL" was defined to be an acronym:
|
126
|
+
#
|
127
|
+
# humanize('ssl_error') # => "SSL error"
|
128
|
+
#
|
129
|
+
def humanize(lower_case_and_underscored_word, capitalize: true, keep_id_suffix: false)
|
108
130
|
result = lower_case_and_underscored_word.to_s.dup
|
131
|
+
|
109
132
|
inflections.humans.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
|
110
|
-
|
111
|
-
result.
|
112
|
-
|
113
|
-
|
114
|
-
|
133
|
+
|
134
|
+
result.sub!(/\A_+/, "".freeze)
|
135
|
+
unless keep_id_suffix
|
136
|
+
result.sub!(/_id\z/, "".freeze)
|
137
|
+
end
|
138
|
+
result.tr!("_".freeze, " ".freeze)
|
139
|
+
|
140
|
+
result.gsub!(/([a-z\d]*)/i) do |match|
|
141
|
+
"#{inflections.acronyms[match.downcase] || match.downcase}"
|
142
|
+
end
|
143
|
+
|
144
|
+
if capitalize
|
145
|
+
result.sub!(/\A\w/) { |match| match.upcase }
|
146
|
+
end
|
147
|
+
|
148
|
+
result
|
149
|
+
end
|
150
|
+
|
151
|
+
# Converts just the first character to uppercase.
|
152
|
+
#
|
153
|
+
# upcase_first('what a Lovely Day') # => "What a Lovely Day"
|
154
|
+
# upcase_first('w') # => "W"
|
155
|
+
# upcase_first('') # => ""
|
156
|
+
def upcase_first(string)
|
157
|
+
string.length > 0 ? string[0].upcase.concat(string[1..-1]) : ""
|
115
158
|
end
|
116
159
|
|
117
160
|
# Capitalizes all the words and replaces some characters in the string to
|
118
161
|
# create a nicer looking title. +titleize+ is meant for creating pretty
|
119
162
|
# output. It is not used in the Rails internals.
|
120
163
|
#
|
164
|
+
# The trailing '_id','Id'.. can be kept and capitalized by setting the
|
165
|
+
# optional parameter +keep_id_suffix+ to true.
|
166
|
+
# By default, this parameter is false.
|
167
|
+
#
|
121
168
|
# +titleize+ is also aliased as +titlecase+.
|
122
169
|
#
|
123
|
-
# 'man from the boondocks'
|
124
|
-
# 'x-men: the last stand'
|
125
|
-
# 'TheManWithoutAPast'
|
126
|
-
# 'raiders_of_the_lost_ark'
|
127
|
-
|
128
|
-
|
170
|
+
# titleize('man from the boondocks') # => "Man From The Boondocks"
|
171
|
+
# titleize('x-men: the last stand') # => "X Men: The Last Stand"
|
172
|
+
# titleize('TheManWithoutAPast') # => "The Man Without A Past"
|
173
|
+
# titleize('raiders_of_the_lost_ark') # => "Raiders Of The Lost Ark"
|
174
|
+
# titleize('string_ending_with_id', keep_id_suffix: true) # => "String Ending With Id"
|
175
|
+
def titleize(word, keep_id_suffix: false)
|
176
|
+
humanize(underscore(word), keep_id_suffix: keep_id_suffix).gsub(/\b(?<!\w['’`])[a-z]/) do |match|
|
177
|
+
match.capitalize
|
178
|
+
end
|
129
179
|
end
|
130
180
|
|
131
|
-
#
|
132
|
-
# method uses the
|
181
|
+
# Creates the name of a table like Rails does for models to table names.
|
182
|
+
# This method uses the #pluralize method on the last word in the string.
|
133
183
|
#
|
134
|
-
# 'RawScaledScorer'
|
135
|
-
# '
|
136
|
-
# 'fancyCategory'
|
184
|
+
# tableize('RawScaledScorer') # => "raw_scaled_scorers"
|
185
|
+
# tableize('ham_and_egg') # => "ham_and_eggs"
|
186
|
+
# tableize('fancyCategory') # => "fancy_categories"
|
137
187
|
def tableize(class_name)
|
138
188
|
pluralize(underscore(class_name))
|
139
189
|
end
|
140
190
|
|
141
|
-
#
|
191
|
+
# Creates a class name from a plural table name like Rails does for table
|
142
192
|
# names to models. Note that this returns a string and not a Class (To
|
143
|
-
# convert to an actual class follow +classify+ with
|
193
|
+
# convert to an actual class follow +classify+ with #constantize).
|
144
194
|
#
|
145
|
-
# '
|
146
|
-
# 'posts'
|
195
|
+
# classify('ham_and_eggs') # => "HamAndEgg"
|
196
|
+
# classify('posts') # => "Post"
|
147
197
|
#
|
148
198
|
# Singular names are not handled correctly:
|
149
199
|
#
|
150
|
-
# '
|
200
|
+
# classify('calculus') # => "Calculus"
|
151
201
|
def classify(table_name)
|
152
202
|
# strip out any leading schema name
|
153
|
-
camelize(singularize(table_name.to_s.sub(/.*\./,
|
203
|
+
camelize(singularize(table_name.to_s.sub(/.*\./, "".freeze)))
|
154
204
|
end
|
155
205
|
|
156
206
|
# Replaces underscores with dashes in the string.
|
157
207
|
#
|
158
|
-
# 'puni_puni'
|
208
|
+
# dasherize('puni_puni') # => "puni-puni"
|
159
209
|
def dasherize(underscored_word)
|
160
|
-
underscored_word.tr(
|
210
|
+
underscored_word.tr("_".freeze, "-".freeze)
|
161
211
|
end
|
162
212
|
|
163
213
|
# Removes the module part from the expression in the string.
|
164
214
|
#
|
165
|
-
# '
|
166
|
-
# 'Inflections'
|
215
|
+
# demodulize('ActiveSupport::Inflector::Inflections') # => "Inflections"
|
216
|
+
# demodulize('Inflections') # => "Inflections"
|
217
|
+
# demodulize('::Inflections') # => "Inflections"
|
218
|
+
# demodulize('') # => ""
|
167
219
|
#
|
168
|
-
# See also
|
220
|
+
# See also #deconstantize.
|
169
221
|
def demodulize(path)
|
170
222
|
path = path.to_s
|
171
|
-
if i = path.rindex(
|
172
|
-
path[(i+2)..-1]
|
223
|
+
if i = path.rindex("::")
|
224
|
+
path[(i + 2)..-1]
|
173
225
|
else
|
174
226
|
path
|
175
227
|
end
|
@@ -177,32 +229,32 @@ module ActiveSupport
|
|
177
229
|
|
178
230
|
# Removes the rightmost segment from the constant expression in the string.
|
179
231
|
#
|
180
|
-
# 'Net::HTTP'
|
181
|
-
# '::Net::HTTP'
|
182
|
-
# 'String'
|
183
|
-
# '::String'
|
184
|
-
# ''
|
232
|
+
# deconstantize('Net::HTTP') # => "Net"
|
233
|
+
# deconstantize('::Net::HTTP') # => "::Net"
|
234
|
+
# deconstantize('String') # => ""
|
235
|
+
# deconstantize('::String') # => ""
|
236
|
+
# deconstantize('') # => ""
|
185
237
|
#
|
186
|
-
# See also
|
238
|
+
# See also #demodulize.
|
187
239
|
def deconstantize(path)
|
188
|
-
path.to_s[0
|
240
|
+
path.to_s[0, path.rindex("::") || 0] # implementation based on the one in facets' Module#spacename
|
189
241
|
end
|
190
242
|
|
191
243
|
# Creates a foreign key name from a class name.
|
192
244
|
# +separate_class_name_and_id_with_underscore+ sets whether
|
193
245
|
# the method should put '_' between the name and 'id'.
|
194
246
|
#
|
195
|
-
# 'Message'
|
196
|
-
# 'Message'
|
197
|
-
# 'Admin::Post'
|
247
|
+
# foreign_key('Message') # => "message_id"
|
248
|
+
# foreign_key('Message', false) # => "messageid"
|
249
|
+
# foreign_key('Admin::Post') # => "post_id"
|
198
250
|
def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
|
199
251
|
underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id")
|
200
252
|
end
|
201
253
|
|
202
254
|
# Tries to find a constant with the name specified in the argument string.
|
203
255
|
#
|
204
|
-
# 'Module'
|
205
|
-
# '
|
256
|
+
# constantize('Module') # => Module
|
257
|
+
# constantize('Foo::Bar') # => Foo::Bar
|
206
258
|
#
|
207
259
|
# The name is assumed to be the one of a top-level constant, no matter
|
208
260
|
# whether it starts with "::" or not. No lexical context is taken into
|
@@ -211,15 +263,20 @@ module ActiveSupport
|
|
211
263
|
# C = 'outside'
|
212
264
|
# module M
|
213
265
|
# C = 'inside'
|
214
|
-
# C
|
215
|
-
# 'C'
|
266
|
+
# C # => 'inside'
|
267
|
+
# constantize('C') # => 'outside', same as ::C
|
216
268
|
# end
|
217
269
|
#
|
218
270
|
# NameError is raised when the name is not in CamelCase or the constant is
|
219
271
|
# unknown.
|
220
272
|
def constantize(camel_cased_word)
|
221
|
-
names = camel_cased_word.split(
|
222
|
-
|
273
|
+
names = camel_cased_word.split("::".freeze)
|
274
|
+
|
275
|
+
# Trigger a built-in NameError exception including the ill-formed constant in the message.
|
276
|
+
Object.const_get(camel_cased_word) if names.empty?
|
277
|
+
|
278
|
+
# Remove the first blank element in case of '::ClassName' notation.
|
279
|
+
names.shift if names.size > 1 && names.first.empty?
|
223
280
|
|
224
281
|
names.inject(Object) do |constant, name|
|
225
282
|
if constant == Object
|
@@ -229,9 +286,9 @@ module ActiveSupport
|
|
229
286
|
next candidate if constant.const_defined?(name, false)
|
230
287
|
next candidate unless Object.const_defined?(name)
|
231
288
|
|
232
|
-
# Go down the ancestors to check
|
233
|
-
#
|
234
|
-
constant = constant.ancestors.inject do |const, ancestor|
|
289
|
+
# Go down the ancestors to check if it is owned directly. The check
|
290
|
+
# stops when we reach Object or the end of ancestors tree.
|
291
|
+
constant = constant.ancestors.inject(constant) do |const, ancestor|
|
235
292
|
break const if ancestor == Object
|
236
293
|
break ancestor if ancestor.const_defined?(name, false)
|
237
294
|
const
|
@@ -245,8 +302,8 @@ module ActiveSupport
|
|
245
302
|
|
246
303
|
# Tries to find a constant with the name specified in the argument string.
|
247
304
|
#
|
248
|
-
# 'Module'
|
249
|
-
# '
|
305
|
+
# safe_constantize('Module') # => Module
|
306
|
+
# safe_constantize('Foo::Bar') # => Foo::Bar
|
250
307
|
#
|
251
308
|
# The name is assumed to be the one of a top-level constant, no matter
|
252
309
|
# whether it starts with "::" or not. No lexical context is taken into
|
@@ -255,23 +312,25 @@ module ActiveSupport
|
|
255
312
|
# C = 'outside'
|
256
313
|
# module M
|
257
314
|
# C = 'inside'
|
258
|
-
# C
|
259
|
-
# 'C'
|
315
|
+
# C # => 'inside'
|
316
|
+
# safe_constantize('C') # => 'outside', same as ::C
|
260
317
|
# end
|
261
318
|
#
|
262
319
|
# +nil+ is returned when the name is not in CamelCase or the constant (or
|
263
320
|
# part of it) is unknown.
|
264
321
|
#
|
265
|
-
# 'blargle'
|
266
|
-
# 'UnknownModule'
|
267
|
-
# 'UnknownModule::Foo::Bar'
|
322
|
+
# safe_constantize('blargle') # => nil
|
323
|
+
# safe_constantize('UnknownModule') # => nil
|
324
|
+
# safe_constantize('UnknownModule::Foo::Bar') # => nil
|
268
325
|
def safe_constantize(camel_cased_word)
|
269
326
|
constantize(camel_cased_word)
|
270
327
|
rescue NameError => e
|
271
|
-
raise
|
272
|
-
e.name.to_s == camel_cased_word.to_s
|
328
|
+
raise if e.name && !(camel_cased_word.to_s.split("::").include?(e.name.to_s) ||
|
329
|
+
e.name.to_s == camel_cased_word.to_s)
|
273
330
|
rescue ArgumentError => e
|
274
|
-
raise unless
|
331
|
+
raise unless /not missing constant #{const_regexp(camel_cased_word)}!$/.match?(e.message)
|
332
|
+
rescue LoadError => e
|
333
|
+
raise unless /Unable to autoload constant #{const_regexp(camel_cased_word)}/.match?(e.message)
|
275
334
|
end
|
276
335
|
|
277
336
|
# Returns the suffix that should be added to a number to denote the position
|
@@ -290,10 +349,10 @@ module ActiveSupport
|
|
290
349
|
"th"
|
291
350
|
else
|
292
351
|
case abs_number % 10
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
352
|
+
when 1; "st"
|
353
|
+
when 2; "nd"
|
354
|
+
when 3; "rd"
|
355
|
+
else "th"
|
297
356
|
end
|
298
357
|
end
|
299
358
|
end
|
@@ -313,30 +372,39 @@ module ActiveSupport
|
|
313
372
|
|
314
373
|
private
|
315
374
|
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
375
|
+
# Mounts a regular expression, returned as a string to ease interpolation,
|
376
|
+
# that will match part by part the given constant.
|
377
|
+
#
|
378
|
+
# const_regexp("Foo::Bar::Baz") # => "Foo(::Bar(::Baz)?)?"
|
379
|
+
# const_regexp("::") # => "::"
|
380
|
+
def const_regexp(camel_cased_word)
|
381
|
+
parts = camel_cased_word.split("::".freeze)
|
382
|
+
|
383
|
+
return Regexp.escape(camel_cased_word) if parts.blank?
|
384
|
+
|
385
|
+
last = parts.pop
|
321
386
|
|
322
|
-
|
323
|
-
|
387
|
+
parts.reverse.inject(last) do |acc, part|
|
388
|
+
part.empty? ? acc : "#{part}(::#{acc})?"
|
389
|
+
end
|
324
390
|
end
|
325
|
-
end
|
326
391
|
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
392
|
+
# Applies inflection rules for +singularize+ and +pluralize+.
|
393
|
+
#
|
394
|
+
# If passed an optional +locale+ parameter, the uncountables will be
|
395
|
+
# found for that locale.
|
396
|
+
#
|
397
|
+
# apply_inflections('post', inflections.plurals, :en) # => "posts"
|
398
|
+
# apply_inflections('posts', inflections.singulars, :en) # => "post"
|
399
|
+
def apply_inflections(word, rules, locale = :en)
|
400
|
+
result = word.to_s.dup
|
333
401
|
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
402
|
+
if word.empty? || inflections(locale).uncountables.uncountable?(result)
|
403
|
+
result
|
404
|
+
else
|
405
|
+
rules.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
|
406
|
+
result
|
407
|
+
end
|
339
408
|
end
|
340
|
-
end
|
341
409
|
end
|
342
410
|
end
|
@@ -1,10 +1,10 @@
|
|
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
|
7
|
-
|
8
8
|
# Replaces non-ASCII characters with an ASCII approximation, or if none
|
9
9
|
# exists, a replacement character which defaults to "?".
|
10
10
|
#
|
@@ -58,40 +58,61 @@ module ActiveSupport
|
|
58
58
|
# I18n.locale = :de
|
59
59
|
# transliterate('Jürgen')
|
60
60
|
# # => "Juergen"
|
61
|
-
def transliterate(string, replacement = "?")
|
62
|
-
|
63
|
-
|
64
|
-
|
61
|
+
def transliterate(string, replacement = "?".freeze)
|
62
|
+
raise ArgumentError, "Can only transliterate strings. Received #{string.class.name}" unless string.is_a?(String)
|
63
|
+
|
64
|
+
I18n.transliterate(
|
65
|
+
ActiveSupport::Multibyte::Unicode.normalize(
|
66
|
+
ActiveSupport::Multibyte::Unicode.tidy_bytes(string), :c),
|
67
|
+
replacement: replacement)
|
65
68
|
end
|
66
69
|
|
67
70
|
# Replaces special characters in a string so that it may be used as part of
|
68
71
|
# a 'pretty' URL.
|
69
72
|
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
73
|
+
# parameterize("Donald E. Knuth") # => "donald-e-knuth"
|
74
|
+
# parameterize("^très|Jolie-- ") # => "tres-jolie"
|
75
|
+
#
|
76
|
+
# To use a custom separator, override the +separator+ argument.
|
77
|
+
#
|
78
|
+
# parameterize("Donald E. Knuth", separator: '_') # => "donald_e_knuth"
|
79
|
+
# parameterize("^très|Jolie__ ", separator: '_') # => "tres_jolie"
|
80
|
+
#
|
81
|
+
# To preserve the case of the characters in a string, use the +preserve_case+ argument.
|
75
82
|
#
|
76
|
-
#
|
77
|
-
#
|
83
|
+
# parameterize("Donald E. Knuth", preserve_case: true) # => "Donald-E-Knuth"
|
84
|
+
# parameterize("^très|Jolie-- ", preserve_case: true) # => "tres-Jolie"
|
78
85
|
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
|
82
|
-
|
86
|
+
# It preserves dashes and underscores unless they are used as separators:
|
87
|
+
#
|
88
|
+
# parameterize("^très|Jolie__ ") # => "tres-jolie__"
|
89
|
+
# parameterize("^très|Jolie-- ", separator: "_") # => "tres_jolie--"
|
90
|
+
# parameterize("^très_Jolie-- ", separator: ".") # => "tres_jolie--"
|
91
|
+
#
|
92
|
+
def parameterize(string, separator: "-", preserve_case: false)
|
93
|
+
# Replace accented chars with their ASCII equivalents.
|
83
94
|
parameterized_string = transliterate(string)
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
95
|
+
|
96
|
+
# Turn unwanted chars into the separator.
|
97
|
+
parameterized_string.gsub!(/[^a-z0-9\-_]+/i, separator)
|
98
|
+
|
99
|
+
unless separator.nil? || separator.empty?
|
100
|
+
if separator == "-".freeze
|
101
|
+
re_duplicate_separator = /-{2,}/
|
102
|
+
re_leading_trailing_separator = /^-|-$/i
|
103
|
+
else
|
104
|
+
re_sep = Regexp.escape(separator)
|
105
|
+
re_duplicate_separator = /#{re_sep}{2,}/
|
106
|
+
re_leading_trailing_separator = /^#{re_sep}|#{re_sep}$/i
|
107
|
+
end
|
88
108
|
# No more than one of the separator in a row.
|
89
|
-
parameterized_string.gsub!(
|
109
|
+
parameterized_string.gsub!(re_duplicate_separator, separator)
|
90
110
|
# Remove leading/trailing separator.
|
91
|
-
parameterized_string.gsub!(
|
111
|
+
parameterized_string.gsub!(re_leading_trailing_separator, "".freeze)
|
92
112
|
end
|
93
|
-
parameterized_string.downcase
|
94
|
-
end
|
95
113
|
|
114
|
+
parameterized_string.downcase! unless preserve_case
|
115
|
+
parameterized_string
|
116
|
+
end
|
96
117
|
end
|
97
118
|
end
|
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# in case active_support/inflector is required without the rest of active_support
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
4
|
+
require "active_support/inflector/inflections"
|
5
|
+
require "active_support/inflector/transliterate"
|
6
|
+
require "active_support/inflector/methods"
|
5
7
|
|
6
|
-
require
|
7
|
-
require
|
8
|
+
require "active_support/inflections"
|
9
|
+
require "active_support/core_ext/string/inflections"
|