activesupport 4.2.11.1 → 5.2.8.1
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 +4 -4
- data/CHANGELOG.md +441 -399
- data/MIT-LICENSE +2 -2
- data/README.rdoc +4 -5
- data/lib/active_support/all.rb +5 -3
- data/lib/active_support/array_inquirer.rb +48 -0
- data/lib/active_support/backtrace_cleaner.rb +7 -5
- data/lib/active_support/benchmarkable.rb +6 -4
- data/lib/active_support/builder.rb +3 -1
- data/lib/active_support/cache/file_store.rb +41 -35
- data/lib/active_support/cache/mem_cache_store.rb +91 -91
- data/lib/active_support/cache/memory_store.rb +27 -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 +67 -34
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
- data/lib/active_support/cache.rb +287 -196
- data/lib/active_support/callbacks.rb +640 -590
- data/lib/active_support/concern.rb +11 -5
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -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 +29 -1
- data/lib/active_support/core_ext/array/conversions.rb +22 -18
- data/lib/active_support/core_ext/array/extract_options.rb +2 -0
- data/lib/active_support/core_ext/array/grouping.rb +11 -18
- data/lib/active_support/core_ext/array/inquiry.rb +19 -0
- data/lib/active_support/core_ext/array/prepend_and_append.rb +5 -3
- data/lib/active_support/core_ext/array/wrap.rb +7 -4
- data/lib/active_support/core_ext/array.rb +9 -6
- data/lib/active_support/core_ext/benchmark.rb +3 -1
- data/lib/active_support/core_ext/big_decimal/conversions.rb +10 -12
- data/lib/active_support/core_ext/big_decimal.rb +3 -1
- data/lib/active_support/core_ext/class/attribute.rb +41 -22
- data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
- data/lib/active_support/core_ext/class/subclasses.rb +20 -6
- data/lib/active_support/core_ext/class.rb +4 -3
- 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 +11 -9
- data/lib/active_support/core_ext/date/conversions.rb +25 -23
- data/lib/active_support/core_ext/date/zones.rb +4 -2
- data/lib/active_support/core_ext/date.rb +6 -4
- data/lib/active_support/core_ext/date_and_time/calculations.rb +170 -58
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +4 -3
- data/lib/active_support/core_ext/date_and_time/zones.rb +12 -12
- 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 +36 -18
- data/lib/active_support/core_ext/date_time/compatibility.rb +8 -6
- data/lib/active_support/core_ext/date_time/conversions.rb +16 -12
- data/lib/active_support/core_ext/date_time.rb +7 -5
- data/lib/active_support/core_ext/digest/uuid.rb +7 -5
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +101 -33
- 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 +14 -9
- data/lib/active_support/core_ext/hash/conversions.rb +62 -41
- data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
- data/lib/active_support/core_ext/hash/except.rb +11 -8
- data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -3
- data/lib/active_support/core_ext/hash/keys.rb +33 -27
- data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
- data/lib/active_support/core_ext/hash/slice.rb +8 -8
- data/lib/active_support/core_ext/hash/transform_values.rb +14 -5
- data/lib/active_support/core_ext/hash.rb +11 -9
- 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 -18
- 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 +5 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -84
- data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
- data/lib/active_support/core_ext/kernel.rb +6 -5
- data/lib/active_support/core_ext/load_error.rb +3 -22
- data/lib/active_support/core_ext/marshal.rb +8 -8
- 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 -9
- data/lib/active_support/core_ext/module/attribute_accessors.rb +43 -40
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +150 -0
- data/lib/active_support/core_ext/module/concerning.rb +11 -12
- data/lib/active_support/core_ext/module/delegation.rb +99 -29
- data/lib/active_support/core_ext/module/deprecation.rb +4 -2
- data/lib/active_support/core_ext/module/introspection.rb +9 -9
- 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 -11
- 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 +78 -81
- data/lib/active_support/core_ext/numeric/inquiry.rb +28 -0
- data/lib/active_support/core_ext/numeric/time.rb +35 -23
- 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 +27 -2
- data/lib/active_support/core_ext/object/conversions.rb +6 -4
- data/lib/active_support/core_ext/object/deep_dup.rb +13 -4
- data/lib/active_support/core_ext/object/duplicable.rb +41 -14
- data/lib/active_support/core_ext/object/inclusion.rb +5 -3
- data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
- data/lib/active_support/core_ext/object/json.rb +49 -19
- data/lib/active_support/core_ext/object/to_param.rb +3 -1
- data/lib/active_support/core_ext/object/to_query.rb +10 -5
- data/lib/active_support/core_ext/object/try.rb +69 -21
- data/lib/active_support/core_ext/object/with_options.rb +16 -3
- data/lib/active_support/core_ext/object.rb +14 -13
- 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 +8 -6
- data/lib/active_support/core_ext/string/behavior.rb +3 -1
- data/lib/active_support/core_ext/string/conversions.rb +7 -4
- data/lib/active_support/core_ext/string/exclude.rb +2 -0
- data/lib/active_support/core_ext/string/filters.rb +6 -5
- data/lib/active_support/core_ext/string/indent.rb +6 -4
- data/lib/active_support/core_ext/string/inflections.rb +61 -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 +62 -38
- 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 -2
- 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 +85 -51
- data/lib/active_support/core_ext/time/compatibility.rb +4 -2
- data/lib/active_support/core_ext/time/conversions.rb +20 -13
- data/lib/active_support/core_ext/time/zones.rb +41 -7
- data/lib/active_support/core_ext/time.rb +7 -6
- data/lib/active_support/core_ext/uri.rb +6 -8
- data/lib/active_support/core_ext.rb +3 -1
- data/lib/active_support/current_attributes.rb +195 -0
- data/lib/active_support/dependencies/autoload.rb +2 -0
- data/lib/active_support/dependencies/interlock.rb +57 -0
- data/lib/active_support/dependencies.rb +152 -161
- data/lib/active_support/deprecation/behaviors.rb +44 -11
- 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 +12 -9
- 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 +314 -38
- 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 +131 -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 +5 -3
- data/lib/active_support/gzip.rb +7 -5
- data/lib/active_support/hash_with_indifferent_access.rb +123 -28
- data/lib/active_support/i18n.rb +8 -6
- data/lib/active_support/i18n_railtie.rb +37 -13
- data/lib/active_support/inflections.rb +13 -11
- data/lib/active_support/inflector/inflections.rb +61 -12
- data/lib/active_support/inflector/methods.rb +163 -136
- data/lib/active_support/inflector/transliterate.rb +48 -27
- data/lib/active_support/inflector.rb +7 -5
- data/lib/active_support/json/decoding.rb +16 -13
- data/lib/active_support/json/encoding.rb +11 -58
- data/lib/active_support/json.rb +4 -2
- data/lib/active_support/key_generator.rb +25 -25
- data/lib/active_support/lazy_load_hooks.rb +50 -20
- 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 +8 -7
- data/lib/active_support/logger_silence.rb +6 -4
- data/lib/active_support/logger_thread_safe_level.rb +7 -5
- data/lib/active_support/message_encryptor.rb +168 -53
- data/lib/active_support/message_verifier.rb +150 -17
- 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 +36 -23
- data/lib/active_support/multibyte/unicode.rb +100 -96
- data/lib/active_support/multibyte.rb +4 -2
- data/lib/active_support/notifications/fanout.rb +11 -9
- data/lib/active_support/notifications/instrumenter.rb +27 -7
- data/lib/active_support/notifications.rb +11 -7
- data/lib/active_support/number_helper/number_converter.rb +13 -11
- data/lib/active_support/number_helper/number_to_currency_converter.rb +9 -9
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +9 -3
- data/lib/active_support/number_helper/number_to_human_converter.rb +11 -9
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +9 -8
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +13 -4
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +23 -56
- data/lib/active_support/number_helper/rounding_helper.rb +66 -0
- data/lib/active_support/number_helper.rb +94 -68
- 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 +23 -5
- data/lib/active_support/per_thread_registry.rb +9 -4
- 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 +15 -11
- data/lib/active_support/string_inquirer.rb +11 -3
- data/lib/active_support/subscriber.rb +21 -16
- data/lib/active_support/tagged_logging.rb +14 -11
- data/lib/active_support/test_case.rb +19 -47
- data/lib/active_support/testing/assertions.rb +137 -20
- data/lib/active_support/testing/autorun.rb +4 -2
- data/lib/active_support/testing/constant_lookup.rb +2 -1
- data/lib/active_support/testing/declarative.rb +3 -1
- 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 +34 -25
- data/lib/active_support/testing/method_call_assertions.rb +43 -0
- data/lib/active_support/testing/setup_and_teardown.rb +13 -8
- data/lib/active_support/testing/stream.rb +44 -0
- data/lib/active_support/testing/tagged_logging.rb +3 -1
- data/lib/active_support/testing/time_helpers.rb +81 -15
- data/lib/active_support/time.rb +14 -12
- data/lib/active_support/time_with_zone.rb +169 -39
- data/lib/active_support/values/time_zone.rb +196 -61
- data/lib/active_support/values/unicode_tables.dat +0 -0
- data/lib/active_support/version.rb +3 -1
- data/lib/active_support/xml_mini/jdom.rb +116 -114
- data/lib/active_support/xml_mini/libxml.rb +16 -13
- data/lib/active_support/xml_mini/libxmlsax.rb +15 -14
- data/lib/active_support/xml_mini/nokogiri.rb +14 -12
- data/lib/active_support/xml_mini/nokogirisax.rb +14 -13
- data/lib/active_support/xml_mini/rexml.rb +11 -9
- data/lib/active_support/xml_mini.rb +37 -37
- data/lib/active_support.rb +12 -11
- metadata +57 -27
- data/lib/active_support/concurrency/latch.rb +0 -27
- data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -16
- data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
- data/lib/active_support/core_ext/date_time/zones.rb +0 -6
- data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
- data/lib/active_support/core_ext/module/method_transplanting.rb +0 -13
- data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
- data/lib/active_support/core_ext/object/itself.rb +0 -15
- data/lib/active_support/core_ext/struct.rb +0 -6
- data/lib/active_support/core_ext/thread.rb +0 -86
- data/lib/active_support/core_ext/time/marshal.rb +0 -30
@@ -1,6 +1,7 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "active_support/inflections"
|
4
|
+
require "active_support/core_ext/regexp"
|
4
5
|
|
5
6
|
module ActiveSupport
|
6
7
|
# The Inflector transforms words from singular to plural, class names to table
|
@@ -22,58 +23,58 @@ module ActiveSupport
|
|
22
23
|
# pluralized using rules defined for that language. By default,
|
23
24
|
# this parameter is set to <tt>:en</tt>.
|
24
25
|
#
|
25
|
-
# 'post'
|
26
|
-
# 'octopus'
|
27
|
-
# 'sheep'
|
28
|
-
# 'words'
|
29
|
-
# 'CamelOctopus'
|
30
|
-
# '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"
|
31
32
|
def pluralize(word, locale = :en)
|
32
|
-
apply_inflections(word, inflections(locale).plurals)
|
33
|
+
apply_inflections(word, inflections(locale).plurals, locale)
|
33
34
|
end
|
34
35
|
|
35
|
-
# The reverse of
|
36
|
+
# The reverse of #pluralize, returns the singular form of a word in a
|
36
37
|
# string.
|
37
38
|
#
|
38
39
|
# If passed an optional +locale+ parameter, the word will be
|
39
40
|
# singularized using rules defined for that language. By default,
|
40
41
|
# this parameter is set to <tt>:en</tt>.
|
41
42
|
#
|
42
|
-
# 'posts'
|
43
|
-
# 'octopi'
|
44
|
-
# 'sheep'
|
45
|
-
# 'word'
|
46
|
-
# 'CamelOctopi'
|
47
|
-
# '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"
|
48
49
|
def singularize(word, locale = :en)
|
49
|
-
apply_inflections(word, inflections(locale).singulars)
|
50
|
+
apply_inflections(word, inflections(locale).singulars, locale)
|
50
51
|
end
|
51
52
|
|
52
|
-
#
|
53
|
-
#
|
53
|
+
# Converts strings to UpperCamelCase.
|
54
|
+
# If the +uppercase_first_letter+ parameter is set to false, then produces
|
54
55
|
# lowerCamelCase.
|
55
56
|
#
|
56
|
-
#
|
57
|
+
# Also converts '/' to '::' which is useful for converting
|
57
58
|
# paths to namespaces.
|
58
59
|
#
|
59
|
-
# 'active_model'
|
60
|
-
# 'active_model'
|
61
|
-
# 'active_model/errors'
|
62
|
-
# '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"
|
63
64
|
#
|
64
65
|
# As a rule of thumb you can think of +camelize+ as the inverse of
|
65
|
-
#
|
66
|
+
# #underscore, though there are cases where that does not hold:
|
66
67
|
#
|
67
|
-
# 'SSLError'
|
68
|
+
# camelize(underscore('SSLError')) # => "SslError"
|
68
69
|
def camelize(term, uppercase_first_letter = true)
|
69
70
|
string = term.to_s
|
70
71
|
if uppercase_first_letter
|
71
|
-
string = string.sub(/^[a-z\d]*/) { inflections.acronyms[
|
72
|
+
string = string.sub(/^[a-z\d]*/) { |match| inflections.acronyms[match] || match.capitalize }
|
72
73
|
else
|
73
|
-
string = string.sub(
|
74
|
+
string = string.sub(inflections.acronyms_camelize_regex) { |match| match.downcase }
|
74
75
|
end
|
75
76
|
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }
|
76
|
-
string.gsub!(
|
77
|
+
string.gsub!("/".freeze, "::".freeze)
|
77
78
|
string
|
78
79
|
end
|
79
80
|
|
@@ -81,125 +82,146 @@ module ActiveSupport
|
|
81
82
|
#
|
82
83
|
# Changes '::' to '/' to convert namespaces to paths.
|
83
84
|
#
|
84
|
-
# 'ActiveModel'
|
85
|
-
# 'ActiveModel::Errors'
|
85
|
+
# underscore('ActiveModel') # => "active_model"
|
86
|
+
# underscore('ActiveModel::Errors') # => "active_model/errors"
|
86
87
|
#
|
87
88
|
# As a rule of thumb you can think of +underscore+ as the inverse of
|
88
|
-
#
|
89
|
+
# #camelize, though there are cases where that does not hold:
|
89
90
|
#
|
90
|
-
# 'SSLError'
|
91
|
+
# camelize(underscore('SSLError')) # => "SslError"
|
91
92
|
def underscore(camel_cased_word)
|
92
|
-
return camel_cased_word unless
|
93
|
-
word = camel_cased_word.to_s.gsub(
|
94
|
-
word.gsub!(
|
95
|
-
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
|
96
|
-
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
97
|
-
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)
|
98
99
|
word.downcase!
|
99
100
|
word
|
100
101
|
end
|
101
102
|
|
102
103
|
# Tweaks an attribute name for display to end users.
|
103
104
|
#
|
104
|
-
# Specifically,
|
105
|
-
#
|
106
|
-
# * Applies human inflection rules to the argument.
|
107
|
-
# * Deletes leading underscores, if any.
|
108
|
-
# * Removes a "_id" suffix if present.
|
109
|
-
# * Replaces underscores with spaces, if any.
|
110
|
-
# * Downcases all words except acronyms.
|
111
|
-
# * Capitalizes the first word.
|
105
|
+
# Specifically, performs these transformations:
|
112
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
113
|
# The capitalization of the first word can be turned off by setting the
|
114
114
|
# +:capitalize+ option to false (default is true).
|
115
115
|
#
|
116
|
-
#
|
117
|
-
#
|
118
|
-
#
|
119
|
-
# humanize('
|
116
|
+
# The trailing '_id' can be kept and capitalized by setting the
|
117
|
+
# optional parameter +keep_id_suffix+ to true (default is false).
|
118
|
+
#
|
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"
|
120
124
|
#
|
121
125
|
# If "SSL" was defined to be an acronym:
|
122
126
|
#
|
123
127
|
# humanize('ssl_error') # => "SSL error"
|
124
128
|
#
|
125
|
-
def humanize(lower_case_and_underscored_word,
|
129
|
+
def humanize(lower_case_and_underscored_word, capitalize: true, keep_id_suffix: false)
|
126
130
|
result = lower_case_and_underscored_word.to_s.dup
|
127
131
|
|
128
132
|
inflections.humans.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
|
129
133
|
|
130
|
-
result.sub!(/\A_+/,
|
131
|
-
|
132
|
-
|
134
|
+
result.sub!(/\A_+/, "".freeze)
|
135
|
+
unless keep_id_suffix
|
136
|
+
result.sub!(/_id\z/, "".freeze)
|
137
|
+
end
|
138
|
+
result.tr!("_".freeze, " ".freeze)
|
133
139
|
|
134
140
|
result.gsub!(/([a-z\d]*)/i) do |match|
|
135
|
-
"#{inflections.acronyms[match] || match.downcase}"
|
141
|
+
"#{inflections.acronyms[match.downcase] || match.downcase}"
|
136
142
|
end
|
137
143
|
|
138
|
-
if
|
144
|
+
if capitalize
|
139
145
|
result.sub!(/\A\w/) { |match| match.upcase }
|
140
146
|
end
|
141
147
|
|
142
148
|
result
|
143
149
|
end
|
144
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]) : ""
|
158
|
+
end
|
159
|
+
|
145
160
|
# Capitalizes all the words and replaces some characters in the string to
|
146
161
|
# create a nicer looking title. +titleize+ is meant for creating pretty
|
147
162
|
# output. It is not used in the Rails internals.
|
148
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
|
+
#
|
149
168
|
# +titleize+ is also aliased as +titlecase+.
|
150
169
|
#
|
151
|
-
# 'man from the boondocks'
|
152
|
-
# 'x-men: the last stand'
|
153
|
-
# 'TheManWithoutAPast'
|
154
|
-
# 'raiders_of_the_lost_ark'
|
155
|
-
|
156
|
-
|
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
|
157
179
|
end
|
158
180
|
|
159
|
-
#
|
160
|
-
# 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.
|
161
183
|
#
|
162
|
-
# 'RawScaledScorer'
|
163
|
-
# '
|
164
|
-
# 'fancyCategory'
|
184
|
+
# tableize('RawScaledScorer') # => "raw_scaled_scorers"
|
185
|
+
# tableize('ham_and_egg') # => "ham_and_eggs"
|
186
|
+
# tableize('fancyCategory') # => "fancy_categories"
|
165
187
|
def tableize(class_name)
|
166
188
|
pluralize(underscore(class_name))
|
167
189
|
end
|
168
190
|
|
169
|
-
#
|
191
|
+
# Creates a class name from a plural table name like Rails does for table
|
170
192
|
# names to models. Note that this returns a string and not a Class (To
|
171
|
-
# convert to an actual class follow +classify+ with
|
193
|
+
# convert to an actual class follow +classify+ with #constantize).
|
172
194
|
#
|
173
|
-
# '
|
174
|
-
# 'posts'
|
195
|
+
# classify('ham_and_eggs') # => "HamAndEgg"
|
196
|
+
# classify('posts') # => "Post"
|
175
197
|
#
|
176
198
|
# Singular names are not handled correctly:
|
177
199
|
#
|
178
|
-
# 'calculus'
|
200
|
+
# classify('calculus') # => "Calculus"
|
179
201
|
def classify(table_name)
|
180
202
|
# strip out any leading schema name
|
181
|
-
camelize(singularize(table_name.to_s.sub(/.*\./,
|
203
|
+
camelize(singularize(table_name.to_s.sub(/.*\./, "".freeze)))
|
182
204
|
end
|
183
205
|
|
184
206
|
# Replaces underscores with dashes in the string.
|
185
207
|
#
|
186
|
-
# 'puni_puni'
|
208
|
+
# dasherize('puni_puni') # => "puni-puni"
|
187
209
|
def dasherize(underscored_word)
|
188
|
-
underscored_word.tr(
|
210
|
+
underscored_word.tr("_".freeze, "-".freeze)
|
189
211
|
end
|
190
212
|
|
191
213
|
# Removes the module part from the expression in the string.
|
192
214
|
#
|
193
|
-
# '
|
194
|
-
# 'Inflections'
|
195
|
-
# '::Inflections'
|
196
|
-
# ''
|
215
|
+
# demodulize('ActiveSupport::Inflector::Inflections') # => "Inflections"
|
216
|
+
# demodulize('Inflections') # => "Inflections"
|
217
|
+
# demodulize('::Inflections') # => "Inflections"
|
218
|
+
# demodulize('') # => ""
|
197
219
|
#
|
198
|
-
# See also
|
220
|
+
# See also #deconstantize.
|
199
221
|
def demodulize(path)
|
200
222
|
path = path.to_s
|
201
|
-
if i = path.rindex(
|
202
|
-
path[(i+2)..-1]
|
223
|
+
if i = path.rindex("::")
|
224
|
+
path[(i + 2)..-1]
|
203
225
|
else
|
204
226
|
path
|
205
227
|
end
|
@@ -207,32 +229,32 @@ module ActiveSupport
|
|
207
229
|
|
208
230
|
# Removes the rightmost segment from the constant expression in the string.
|
209
231
|
#
|
210
|
-
# 'Net::HTTP'
|
211
|
-
# '::Net::HTTP'
|
212
|
-
# 'String'
|
213
|
-
# '::String'
|
214
|
-
# ''
|
232
|
+
# deconstantize('Net::HTTP') # => "Net"
|
233
|
+
# deconstantize('::Net::HTTP') # => "::Net"
|
234
|
+
# deconstantize('String') # => ""
|
235
|
+
# deconstantize('::String') # => ""
|
236
|
+
# deconstantize('') # => ""
|
215
237
|
#
|
216
|
-
# See also
|
238
|
+
# See also #demodulize.
|
217
239
|
def deconstantize(path)
|
218
|
-
path.to_s[0, path.rindex(
|
240
|
+
path.to_s[0, path.rindex("::") || 0] # implementation based on the one in facets' Module#spacename
|
219
241
|
end
|
220
242
|
|
221
243
|
# Creates a foreign key name from a class name.
|
222
244
|
# +separate_class_name_and_id_with_underscore+ sets whether
|
223
245
|
# the method should put '_' between the name and 'id'.
|
224
246
|
#
|
225
|
-
# 'Message'
|
226
|
-
# 'Message'
|
227
|
-
# 'Admin::Post'
|
247
|
+
# foreign_key('Message') # => "message_id"
|
248
|
+
# foreign_key('Message', false) # => "messageid"
|
249
|
+
# foreign_key('Admin::Post') # => "post_id"
|
228
250
|
def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
|
229
251
|
underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id")
|
230
252
|
end
|
231
253
|
|
232
254
|
# Tries to find a constant with the name specified in the argument string.
|
233
255
|
#
|
234
|
-
# 'Module'
|
235
|
-
# '
|
256
|
+
# constantize('Module') # => Module
|
257
|
+
# constantize('Foo::Bar') # => Foo::Bar
|
236
258
|
#
|
237
259
|
# The name is assumed to be the one of a top-level constant, no matter
|
238
260
|
# whether it starts with "::" or not. No lexical context is taken into
|
@@ -241,14 +263,14 @@ module ActiveSupport
|
|
241
263
|
# C = 'outside'
|
242
264
|
# module M
|
243
265
|
# C = 'inside'
|
244
|
-
# C
|
245
|
-
# 'C'
|
266
|
+
# C # => 'inside'
|
267
|
+
# constantize('C') # => 'outside', same as ::C
|
246
268
|
# end
|
247
269
|
#
|
248
270
|
# NameError is raised when the name is not in CamelCase or the constant is
|
249
271
|
# unknown.
|
250
272
|
def constantize(camel_cased_word)
|
251
|
-
names = camel_cased_word.split(
|
273
|
+
names = camel_cased_word.split("::".freeze)
|
252
274
|
|
253
275
|
# Trigger a built-in NameError exception including the ill-formed constant in the message.
|
254
276
|
Object.const_get(camel_cased_word) if names.empty?
|
@@ -266,7 +288,7 @@ module ActiveSupport
|
|
266
288
|
|
267
289
|
# Go down the ancestors to check if it is owned directly. The check
|
268
290
|
# stops when we reach Object or the end of ancestors tree.
|
269
|
-
constant = constant.ancestors.inject do |const, ancestor|
|
291
|
+
constant = constant.ancestors.inject(constant) do |const, ancestor|
|
270
292
|
break const if ancestor == Object
|
271
293
|
break ancestor if ancestor.const_defined?(name, false)
|
272
294
|
const
|
@@ -280,8 +302,8 @@ module ActiveSupport
|
|
280
302
|
|
281
303
|
# Tries to find a constant with the name specified in the argument string.
|
282
304
|
#
|
283
|
-
# 'Module'
|
284
|
-
# '
|
305
|
+
# safe_constantize('Module') # => Module
|
306
|
+
# safe_constantize('Foo::Bar') # => Foo::Bar
|
285
307
|
#
|
286
308
|
# The name is assumed to be the one of a top-level constant, no matter
|
287
309
|
# whether it starts with "::" or not. No lexical context is taken into
|
@@ -290,23 +312,25 @@ module ActiveSupport
|
|
290
312
|
# C = 'outside'
|
291
313
|
# module M
|
292
314
|
# C = 'inside'
|
293
|
-
# C
|
294
|
-
# 'C'
|
315
|
+
# C # => 'inside'
|
316
|
+
# safe_constantize('C') # => 'outside', same as ::C
|
295
317
|
# end
|
296
318
|
#
|
297
319
|
# +nil+ is returned when the name is not in CamelCase or the constant (or
|
298
320
|
# part of it) is unknown.
|
299
321
|
#
|
300
|
-
# 'blargle'
|
301
|
-
# 'UnknownModule'
|
302
|
-
# 'UnknownModule::Foo::Bar'
|
322
|
+
# safe_constantize('blargle') # => nil
|
323
|
+
# safe_constantize('UnknownModule') # => nil
|
324
|
+
# safe_constantize('UnknownModule::Foo::Bar') # => nil
|
303
325
|
def safe_constantize(camel_cased_word)
|
304
326
|
constantize(camel_cased_word)
|
305
327
|
rescue NameError => e
|
306
328
|
raise if e.name && !(camel_cased_word.to_s.split("::").include?(e.name.to_s) ||
|
307
329
|
e.name.to_s == camel_cased_word.to_s)
|
308
330
|
rescue ArgumentError => e
|
309
|
-
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)
|
310
334
|
end
|
311
335
|
|
312
336
|
# Returns the suffix that should be added to a number to denote the position
|
@@ -325,10 +349,10 @@ module ActiveSupport
|
|
325
349
|
"th"
|
326
350
|
else
|
327
351
|
case abs_number % 10
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
352
|
+
when 1; "st"
|
353
|
+
when 2; "nd"
|
354
|
+
when 3; "rd"
|
355
|
+
else "th"
|
332
356
|
end
|
333
357
|
end
|
334
358
|
end
|
@@ -348,36 +372,39 @@ module ActiveSupport
|
|
348
372
|
|
349
373
|
private
|
350
374
|
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
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)
|
358
382
|
|
359
|
-
|
383
|
+
return Regexp.escape(camel_cased_word) if parts.blank?
|
360
384
|
|
361
|
-
|
385
|
+
last = parts.pop
|
362
386
|
|
363
|
-
|
364
|
-
|
387
|
+
parts.reverse.inject(last) do |acc, part|
|
388
|
+
part.empty? ? acc : "#{part}(::#{acc})?"
|
389
|
+
end
|
365
390
|
end
|
366
|
-
end
|
367
|
-
|
368
|
-
# Applies inflection rules for +singularize+ and +pluralize+.
|
369
|
-
#
|
370
|
-
# apply_inflections('post', inflections.plurals) # => "posts"
|
371
|
-
# apply_inflections('posts', inflections.singulars) # => "post"
|
372
|
-
def apply_inflections(word, rules)
|
373
|
-
result = word.to_s.dup
|
374
391
|
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
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
|
401
|
+
|
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
|
380
408
|
end
|
381
|
-
end
|
382
409
|
end
|
383
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"
|