activesupport 4.2.11.3 → 5.0.0.beta1
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 +309 -485
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -3
- data/lib/active_support.rb +8 -15
- data/lib/active_support/array_inquirer.rb +44 -0
- data/lib/active_support/backtrace_cleaner.rb +1 -1
- data/lib/active_support/cache.rb +59 -72
- data/lib/active_support/cache/file_store.rb +27 -19
- data/lib/active_support/cache/mem_cache_store.rb +71 -60
- data/lib/active_support/cache/memory_store.rb +16 -21
- data/lib/active_support/cache/null_store.rb +1 -4
- data/lib/active_support/cache/strategy/local_cache.rb +31 -20
- data/lib/active_support/callbacks.rb +107 -111
- data/lib/active_support/concern.rb +1 -1
- data/lib/active_support/concurrency/latch.rb +7 -15
- data/lib/active_support/concurrency/share_lock.rb +142 -0
- data/lib/active_support/configurable.rb +1 -0
- data/lib/active_support/core_ext.rb +2 -1
- data/lib/active_support/core_ext/array.rb +1 -0
- data/lib/active_support/core_ext/array/access.rb +13 -1
- data/lib/active_support/core_ext/array/conversions.rb +6 -4
- data/lib/active_support/core_ext/array/inquiry.rb +17 -0
- data/lib/active_support/core_ext/array/wrap.rb +5 -4
- data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -10
- data/lib/active_support/core_ext/class.rb +0 -1
- data/lib/active_support/core_ext/class/attribute.rb +10 -9
- data/lib/active_support/core_ext/class/subclasses.rb +5 -2
- data/lib/active_support/core_ext/date.rb +1 -1
- data/lib/active_support/core_ext/date/blank.rb +12 -0
- data/lib/active_support/core_ext/date/calculations.rb +1 -1
- data/lib/active_support/core_ext/date/conversions.rb +3 -3
- data/lib/active_support/core_ext/date_and_time/calculations.rb +93 -27
- data/lib/active_support/core_ext/date_and_time/zones.rb +1 -2
- data/lib/active_support/core_ext/date_time.rb +1 -1
- data/lib/active_support/core_ext/date_time/blank.rb +12 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +7 -23
- data/lib/active_support/core_ext/date_time/conversions.rb +2 -0
- data/lib/active_support/core_ext/enumerable.rb +27 -17
- data/lib/active_support/core_ext/file/atomic.rb +30 -25
- data/lib/active_support/core_ext/hash/compact.rb +15 -19
- data/lib/active_support/core_ext/hash/conversions.rb +21 -2
- data/lib/active_support/core_ext/hash/deep_merge.rb +1 -1
- data/lib/active_support/core_ext/hash/except.rb +9 -8
- data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -1
- data/lib/active_support/core_ext/hash/keys.rb +22 -18
- data/lib/active_support/core_ext/hash/slice.rb +1 -1
- data/lib/active_support/core_ext/hash/transform_values.rb +13 -7
- data/lib/active_support/core_ext/integer/time.rb +1 -1
- data/lib/active_support/core_ext/kernel.rb +0 -1
- data/lib/active_support/core_ext/kernel/debugger.rb +3 -10
- data/lib/active_support/core_ext/kernel/reporting.rb +0 -84
- data/lib/active_support/core_ext/load_error.rb +4 -2
- data/lib/active_support/core_ext/marshal.rb +8 -13
- data/lib/active_support/core_ext/module.rb +1 -0
- data/lib/active_support/core_ext/module/aliasing.rb +6 -1
- data/lib/active_support/core_ext/module/anonymous.rb +10 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -5
- data/lib/active_support/core_ext/module/attribute_accessors.rb +7 -7
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +141 -0
- data/lib/active_support/core_ext/module/concerning.rb +4 -4
- data/lib/active_support/core_ext/module/delegation.rb +7 -14
- data/lib/active_support/core_ext/module/method_transplanting.rb +3 -13
- data/lib/active_support/core_ext/module/qualified_const.rb +30 -12
- data/lib/active_support/core_ext/module/remove_method.rb +23 -0
- data/lib/active_support/core_ext/name_error.rb +15 -2
- data/lib/active_support/core_ext/numeric.rb +1 -0
- data/lib/active_support/core_ext/numeric/bytes.rb +20 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +12 -23
- data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
- data/lib/active_support/core_ext/numeric/time.rb +20 -0
- data/lib/active_support/core_ext/object.rb +0 -1
- data/lib/active_support/core_ext/object/blank.rb +11 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +10 -3
- data/lib/active_support/core_ext/object/duplicable.rb +39 -70
- data/lib/active_support/core_ext/object/inclusion.rb +2 -2
- data/lib/active_support/core_ext/object/instance_variables.rb +1 -1
- data/lib/active_support/core_ext/object/json.rb +9 -7
- data/lib/active_support/core_ext/object/to_query.rb +1 -1
- data/lib/active_support/core_ext/object/try.rb +67 -21
- data/lib/active_support/core_ext/object/with_options.rb +1 -1
- data/lib/active_support/core_ext/range/conversions.rb +18 -6
- data/lib/active_support/core_ext/range/each.rb +16 -18
- data/lib/active_support/core_ext/range/include_range.rb +20 -20
- data/lib/active_support/core_ext/securerandom.rb +23 -0
- data/lib/active_support/core_ext/string/access.rb +1 -1
- data/lib/active_support/core_ext/string/behavior.rb +1 -1
- data/lib/active_support/core_ext/string/conversions.rb +2 -2
- data/lib/active_support/core_ext/string/filters.rb +1 -2
- data/lib/active_support/core_ext/string/inflections.rb +23 -5
- data/lib/active_support/core_ext/string/multibyte.rb +11 -7
- data/lib/active_support/core_ext/string/output_safety.rb +8 -9
- data/lib/active_support/core_ext/string/strip.rb +3 -6
- data/lib/active_support/core_ext/struct.rb +3 -6
- data/lib/active_support/core_ext/time.rb +0 -2
- data/lib/active_support/core_ext/time/calculations.rb +18 -16
- data/lib/active_support/core_ext/time/conversions.rb +4 -2
- data/lib/active_support/core_ext/time/marshal.rb +2 -29
- data/lib/active_support/core_ext/time/zones.rb +19 -3
- data/lib/active_support/core_ext/uri.rb +1 -3
- data/lib/active_support/dependencies.rb +79 -44
- data/lib/active_support/dependencies/interlock.rb +47 -0
- data/lib/active_support/deprecation/behaviors.rb +12 -0
- data/lib/active_support/deprecation/method_wrappers.rb +42 -16
- data/lib/active_support/deprecation/proxy_wrappers.rb +47 -24
- data/lib/active_support/deprecation/reporting.rb +13 -2
- data/lib/active_support/duration.rb +5 -8
- data/lib/active_support/evented_file_update_checker.rb +150 -0
- data/lib/active_support/file_update_checker.rb +1 -1
- data/lib/active_support/gem_version.rb +5 -5
- data/lib/active_support/hash_with_indifferent_access.rb +15 -17
- data/lib/active_support/i18n_railtie.rb +25 -4
- data/lib/active_support/inflector/inflections.rb +36 -5
- data/lib/active_support/inflector/methods.rb +87 -89
- data/lib/active_support/inflector/transliterate.rb +36 -21
- data/lib/active_support/json/decoding.rb +2 -8
- data/lib/active_support/json/encoding.rb +0 -50
- data/lib/active_support/key_generator.rb +4 -4
- data/lib/active_support/log_subscriber.rb +1 -1
- data/lib/active_support/log_subscriber/test_helper.rb +3 -3
- data/lib/active_support/logger.rb +4 -52
- data/lib/active_support/logger_silence.rb +3 -5
- data/lib/active_support/message_encryptor.rb +4 -11
- data/lib/active_support/message_verifier.rb +64 -8
- data/lib/active_support/multibyte/chars.rb +12 -3
- data/lib/active_support/multibyte/unicode.rb +6 -8
- data/lib/active_support/notifications.rb +2 -2
- data/lib/active_support/notifications/fanout.rb +5 -5
- data/lib/active_support/notifications/instrumenter.rb +19 -2
- data/lib/active_support/number_helper.rb +21 -15
- data/lib/active_support/number_helper/number_to_currency_converter.rb +4 -4
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +7 -2
- data/lib/active_support/number_helper/number_to_human_converter.rb +6 -4
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +5 -1
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +28 -25
- data/lib/active_support/ordered_options.rb +15 -1
- data/lib/active_support/per_thread_registry.rb +3 -0
- data/lib/active_support/rails.rb +2 -2
- data/lib/active_support/railtie.rb +6 -1
- data/lib/active_support/rescuable.rb +4 -4
- data/lib/active_support/security_utils.rb +0 -7
- data/lib/active_support/string_inquirer.rb +1 -1
- data/lib/active_support/subscriber.rb +5 -10
- data/lib/active_support/tagged_logging.rb +3 -1
- data/lib/active_support/test_case.rb +13 -25
- data/lib/active_support/testing/assertions.rb +15 -13
- data/lib/active_support/testing/autorun.rb +8 -1
- data/lib/active_support/testing/composite_filter.rb +54 -0
- data/lib/active_support/testing/deprecation.rb +9 -8
- data/lib/active_support/testing/file_fixtures.rb +34 -0
- data/lib/active_support/testing/isolation.rb +22 -8
- data/lib/active_support/testing/method_call_assertions.rb +41 -0
- data/lib/active_support/testing/stream.rb +42 -0
- data/lib/active_support/testing/time_helpers.rb +6 -6
- data/lib/active_support/time_with_zone.rb +135 -53
- data/lib/active_support/values/time_zone.rb +80 -46
- data/lib/active_support/values/unicode_tables.dat +0 -0
- data/lib/active_support/xml_mini.rb +15 -30
- data/lib/active_support/xml_mini/jdom.rb +1 -1
- data/lib/active_support/xml_mini/libxml.rb +5 -3
- data/lib/active_support/xml_mini/libxmlsax.rb +4 -1
- data/lib/active_support/xml_mini/nokogiri.rb +5 -3
- data/lib/active_support/xml_mini/nokogirisax.rb +3 -1
- data/lib/active_support/xml_mini/rexml.rb +3 -1
- metadata +57 -21
- 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_and_time/compatibility.rb +0 -15
- data/lib/active_support/core_ext/date_time/compatibility.rb +0 -16
- data/lib/active_support/core_ext/object/itself.rb +0 -15
- data/lib/active_support/core_ext/thread.rb +0 -86
- data/lib/active_support/core_ext/time/compatibility.rb +0 -14
- data/lib/active_support/logger_thread_safe_level.rb +0 -32
@@ -35,7 +35,7 @@ module ActiveSupport
|
|
35
35
|
# This method must also receive a block that will be called once a path
|
36
36
|
# changes. The array of files and list of directories cannot be changed
|
37
37
|
# after FileUpdateChecker has been initialized.
|
38
|
-
def initialize(files, dirs={}, &block)
|
38
|
+
def initialize(files, dirs = {}, &block)
|
39
39
|
@files = files.freeze
|
40
40
|
@glob = compile_glob(dirs)
|
41
41
|
@block = block
|
@@ -1,14 +1,14 @@
|
|
1
1
|
module ActiveSupport
|
2
|
-
# Returns the version of the currently loaded Active Support as a <tt>Gem::Version</tt
|
2
|
+
# Returns the version of the currently loaded Active Support as a <tt>Gem::Version</tt>.
|
3
3
|
def self.gem_version
|
4
4
|
Gem::Version.new VERSION::STRING
|
5
5
|
end
|
6
6
|
|
7
7
|
module VERSION
|
8
|
-
MAJOR =
|
9
|
-
MINOR =
|
10
|
-
TINY =
|
11
|
-
PRE = "
|
8
|
+
MAJOR = 5
|
9
|
+
MINOR = 0
|
10
|
+
TINY = 0
|
11
|
+
PRE = "beta1"
|
12
12
|
|
13
13
|
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
|
14
14
|
end
|
@@ -59,6 +59,10 @@ module ActiveSupport
|
|
59
59
|
if constructor.respond_to?(:to_hash)
|
60
60
|
super()
|
61
61
|
update(constructor)
|
62
|
+
|
63
|
+
hash = constructor.to_hash
|
64
|
+
self.default = hash.default if hash.default
|
65
|
+
self.default_proc = hash.default_proc if hash.default_proc
|
62
66
|
else
|
63
67
|
super(constructor)
|
64
68
|
end
|
@@ -73,11 +77,12 @@ module ActiveSupport
|
|
73
77
|
end
|
74
78
|
|
75
79
|
def self.new_from_hash_copying_default(hash)
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
80
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
81
|
+
`ActiveSupport::HashWithIndifferentAccess.new_from_hash_copying_default`
|
82
|
+
has been deprecated, and will be removed in Rails 5.1. The behavior of
|
83
|
+
this method is now identical to the behavior of `.new`.
|
84
|
+
MSG
|
85
|
+
new(hash)
|
81
86
|
end
|
82
87
|
|
83
88
|
def self.[](*args)
|
@@ -92,7 +97,7 @@ module ActiveSupport
|
|
92
97
|
# hash = ActiveSupport::HashWithIndifferentAccess.new
|
93
98
|
# hash[:key] = 'value'
|
94
99
|
#
|
95
|
-
# This value can be later fetched using either +:key+ or
|
100
|
+
# This value can be later fetched using either +:key+ or <tt>'key'</tt>.
|
96
101
|
def []=(key, value)
|
97
102
|
regular_writer(convert_key(key), convert_value(value, for: :assignment))
|
98
103
|
end
|
@@ -206,7 +211,7 @@ module ActiveSupport
|
|
206
211
|
# hash['a'] = nil
|
207
212
|
# hash.reverse_merge(a: 0, b: 1) # => {"a"=>nil, "b"=>1}
|
208
213
|
def reverse_merge(other_hash)
|
209
|
-
super(self.class.
|
214
|
+
super(self.class.new(other_hash))
|
210
215
|
end
|
211
216
|
|
212
217
|
# Same semantics as +reverse_merge+ but modifies the receiver in-place.
|
@@ -219,7 +224,7 @@ module ActiveSupport
|
|
219
224
|
# h = { "a" => 100, "b" => 200 }
|
220
225
|
# h.replace({ "c" => 300, "d" => 400 }) # => {"c"=>300, "d"=>400}
|
221
226
|
def replace(other_hash)
|
222
|
-
super(self.class.
|
227
|
+
super(self.class.new(other_hash))
|
223
228
|
end
|
224
229
|
|
225
230
|
# Removes the specified key from the hash.
|
@@ -238,22 +243,15 @@ module ActiveSupport
|
|
238
243
|
def to_options!; self end
|
239
244
|
|
240
245
|
def select(*args, &block)
|
246
|
+
return to_enum(:select) unless block_given?
|
241
247
|
dup.tap { |hash| hash.select!(*args, &block) }
|
242
248
|
end
|
243
249
|
|
244
250
|
def reject(*args, &block)
|
251
|
+
return to_enum(:reject) unless block_given?
|
245
252
|
dup.tap { |hash| hash.reject!(*args, &block) }
|
246
253
|
end
|
247
254
|
|
248
|
-
def transform_values(*args, &block)
|
249
|
-
return to_enum(:transform_values) unless block_given?
|
250
|
-
dup.tap { |hash| hash.transform_values!(*args, &block) }
|
251
|
-
end
|
252
|
-
|
253
|
-
def compact
|
254
|
-
dup.tap(&:compact!)
|
255
|
-
end
|
256
|
-
|
257
255
|
# Convert to a regular hash with string keys.
|
258
256
|
def to_hash
|
259
257
|
_new_hash = Hash.new
|
@@ -37,10 +37,12 @@ module I18n
|
|
37
37
|
enforce_available_locales = I18n.enforce_available_locales if enforce_available_locales.nil?
|
38
38
|
I18n.enforce_available_locales = false
|
39
39
|
|
40
|
+
reloadable_paths = []
|
40
41
|
app.config.i18n.each do |setting, value|
|
41
42
|
case setting
|
42
43
|
when :railties_load_path
|
43
|
-
|
44
|
+
reloadable_paths = value
|
45
|
+
app.config.i18n.load_path.unshift(*value.map(&:existent).flatten)
|
44
46
|
when :load_path
|
45
47
|
I18n.load_path += value
|
46
48
|
else
|
@@ -53,16 +55,29 @@ module I18n
|
|
53
55
|
# Restore available locales check so it will take place from now on.
|
54
56
|
I18n.enforce_available_locales = enforce_available_locales
|
55
57
|
|
56
|
-
|
58
|
+
directories = watched_dirs_with_extensions(reloadable_paths)
|
59
|
+
reloader = app.config.file_watcher.new(I18n.load_path.dup, directories) do
|
60
|
+
I18n.load_path.keep_if { |p| File.exist?(p) }
|
61
|
+
I18n.load_path |= reloadable_paths.map(&:existent).flatten
|
62
|
+
|
63
|
+
I18n.reload!
|
64
|
+
end
|
65
|
+
|
57
66
|
app.reloaders << reloader
|
58
|
-
ActionDispatch::Reloader.to_prepare
|
67
|
+
ActionDispatch::Reloader.to_prepare do
|
68
|
+
reloader.execute_if_updated
|
69
|
+
# TODO: remove the following line as soon as the return value of
|
70
|
+
# callbacks is ignored, that is, returning `false` does not
|
71
|
+
# display a deprecation warning or halts the callback chain.
|
72
|
+
true
|
73
|
+
end
|
59
74
|
reloader.execute
|
60
75
|
|
61
76
|
@i18n_inited = true
|
62
77
|
end
|
63
78
|
|
64
79
|
def self.include_fallbacks_module
|
65
|
-
I18n.backend.class.
|
80
|
+
I18n.backend.class.include(I18n::Backend::Fallbacks)
|
66
81
|
end
|
67
82
|
|
68
83
|
def self.init_fallbacks(fallbacks)
|
@@ -90,5 +105,11 @@ module I18n
|
|
90
105
|
raise "Unexpected fallback type #{fallbacks.inspect}"
|
91
106
|
end
|
92
107
|
end
|
108
|
+
|
109
|
+
def self.watched_dirs_with_extensions(paths)
|
110
|
+
paths.each_with_object({}) do |path, result|
|
111
|
+
result[path.absolute_current] = path.extensions
|
112
|
+
end
|
113
|
+
end
|
93
114
|
end
|
94
115
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'concurrent/map'
|
2
2
|
require 'active_support/core_ext/array/prepend_and_append'
|
3
3
|
require 'active_support/i18n'
|
4
4
|
|
@@ -25,7 +25,38 @@ module ActiveSupport
|
|
25
25
|
# singularization rules that is runs. This guarantees that your rules run
|
26
26
|
# before any of the rules that may already have been loaded.
|
27
27
|
class Inflections
|
28
|
-
@__instance__ =
|
28
|
+
@__instance__ = Concurrent::Map.new
|
29
|
+
|
30
|
+
class Uncountables < Array
|
31
|
+
def initialize
|
32
|
+
@regex_array = []
|
33
|
+
super
|
34
|
+
end
|
35
|
+
|
36
|
+
def delete(entry)
|
37
|
+
super entry
|
38
|
+
@regex_array.delete(to_regex(entry))
|
39
|
+
end
|
40
|
+
|
41
|
+
def <<(*word)
|
42
|
+
add(word)
|
43
|
+
end
|
44
|
+
|
45
|
+
def add(words)
|
46
|
+
self.concat(words.flatten.map(&:downcase))
|
47
|
+
@regex_array += self.map {|word| to_regex(word) }
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
def uncountable?(str)
|
52
|
+
@regex_array.any? { |regex| regex === str }
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
def to_regex(string)
|
57
|
+
/\b#{::Regexp.escape(string)}\Z/i
|
58
|
+
end
|
59
|
+
end
|
29
60
|
|
30
61
|
def self.instance(locale = :en)
|
31
62
|
@__instance__[locale] ||= new
|
@@ -34,7 +65,7 @@ module ActiveSupport
|
|
34
65
|
attr_reader :plurals, :singulars, :uncountables, :humans, :acronyms, :acronym_regex
|
35
66
|
|
36
67
|
def initialize
|
37
|
-
@plurals, @singulars, @uncountables, @humans, @acronyms, @acronym_regex = [], [],
|
68
|
+
@plurals, @singulars, @uncountables, @humans, @acronyms, @acronym_regex = [], [], Uncountables.new, [], {}, /(?=a)b/
|
38
69
|
end
|
39
70
|
|
40
71
|
# Private, for the test suite.
|
@@ -160,7 +191,7 @@ module ActiveSupport
|
|
160
191
|
# uncountable 'money', 'information'
|
161
192
|
# uncountable %w( money information rice )
|
162
193
|
def uncountable(*words)
|
163
|
-
@uncountables
|
194
|
+
@uncountables.add(words)
|
164
195
|
end
|
165
196
|
|
166
197
|
# Specifies a humanized form of a string by a regular expression rule or
|
@@ -185,7 +216,7 @@ module ActiveSupport
|
|
185
216
|
def clear(scope = :all)
|
186
217
|
case scope
|
187
218
|
when :all
|
188
|
-
@plurals, @singulars, @uncountables, @humans = [], [],
|
219
|
+
@plurals, @singulars, @uncountables, @humans = [], [], Uncountables.new, []
|
189
220
|
else
|
190
221
|
instance_variable_set "@#{scope}", []
|
191
222
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
require 'active_support/inflections'
|
4
2
|
|
5
3
|
module ActiveSupport
|
@@ -22,58 +20,58 @@ module ActiveSupport
|
|
22
20
|
# pluralized using rules defined for that language. By default,
|
23
21
|
# this parameter is set to <tt>:en</tt>.
|
24
22
|
#
|
25
|
-
# 'post'
|
26
|
-
# 'octopus'
|
27
|
-
# 'sheep'
|
28
|
-
# 'words'
|
29
|
-
# 'CamelOctopus'
|
30
|
-
# 'ley'
|
23
|
+
# pluralize('post') # => "posts"
|
24
|
+
# pluralize('octopus') # => "octopi"
|
25
|
+
# pluralize('sheep') # => "sheep"
|
26
|
+
# pluralize('words') # => "words"
|
27
|
+
# pluralize('CamelOctopus') # => "CamelOctopi"
|
28
|
+
# pluralize('ley', :es) # => "leyes"
|
31
29
|
def pluralize(word, locale = :en)
|
32
30
|
apply_inflections(word, inflections(locale).plurals)
|
33
31
|
end
|
34
32
|
|
35
|
-
# The reverse of
|
33
|
+
# The reverse of #pluralize, returns the singular form of a word in a
|
36
34
|
# string.
|
37
35
|
#
|
38
36
|
# If passed an optional +locale+ parameter, the word will be
|
39
37
|
# singularized using rules defined for that language. By default,
|
40
38
|
# this parameter is set to <tt>:en</tt>.
|
41
39
|
#
|
42
|
-
# 'posts'
|
43
|
-
# 'octopi'
|
44
|
-
# 'sheep'
|
45
|
-
# 'word'
|
46
|
-
# 'CamelOctopi'
|
47
|
-
# 'leyes'
|
40
|
+
# singularize('posts') # => "post"
|
41
|
+
# singularize('octopi') # => "octopus"
|
42
|
+
# singularize('sheep') # => "sheep"
|
43
|
+
# singularize('word') # => "word"
|
44
|
+
# singularize('CamelOctopi') # => "CamelOctopus"
|
45
|
+
# singularize('leyes', :es) # => "ley"
|
48
46
|
def singularize(word, locale = :en)
|
49
47
|
apply_inflections(word, inflections(locale).singulars)
|
50
48
|
end
|
51
49
|
|
52
|
-
#
|
53
|
-
#
|
50
|
+
# Converts strings to UpperCamelCase.
|
51
|
+
# If the +uppercase_first_letter+ parameter is set to false, then produces
|
54
52
|
# lowerCamelCase.
|
55
53
|
#
|
56
|
-
#
|
54
|
+
# Also converts '/' to '::' which is useful for converting
|
57
55
|
# paths to namespaces.
|
58
56
|
#
|
59
|
-
# 'active_model'
|
60
|
-
# 'active_model'
|
61
|
-
# 'active_model/errors'
|
62
|
-
# 'active_model/errors'
|
57
|
+
# camelize('active_model') # => "ActiveModel"
|
58
|
+
# camelize('active_model', false) # => "activeModel"
|
59
|
+
# camelize('active_model/errors') # => "ActiveModel::Errors"
|
60
|
+
# camelize('active_model/errors', false) # => "activeModel::Errors"
|
63
61
|
#
|
64
62
|
# As a rule of thumb you can think of +camelize+ as the inverse of
|
65
|
-
#
|
63
|
+
# #underscore, though there are cases where that does not hold:
|
66
64
|
#
|
67
|
-
# 'SSLError'
|
65
|
+
# camelize(underscore('SSLError')) # => "SslError"
|
68
66
|
def camelize(term, uppercase_first_letter = true)
|
69
67
|
string = term.to_s
|
70
68
|
if uppercase_first_letter
|
71
|
-
string = string.sub(/^[a-z\d]*/) { inflections.acronyms[
|
69
|
+
string = string.sub(/^[a-z\d]*/) { |match| inflections.acronyms[match] || match.capitalize }
|
72
70
|
else
|
73
|
-
string = string.sub(/^(?:#{inflections.acronym_regex}(?=\b|[A-Z_])|\w)/) {
|
71
|
+
string = string.sub(/^(?:#{inflections.acronym_regex}(?=\b|[A-Z_])|\w)/) { |match| match.downcase }
|
74
72
|
end
|
75
73
|
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }
|
76
|
-
string.gsub!(
|
74
|
+
string.gsub!('/'.freeze, '::'.freeze)
|
77
75
|
string
|
78
76
|
end
|
79
77
|
|
@@ -81,34 +79,34 @@ module ActiveSupport
|
|
81
79
|
#
|
82
80
|
# Changes '::' to '/' to convert namespaces to paths.
|
83
81
|
#
|
84
|
-
# 'ActiveModel'
|
85
|
-
# 'ActiveModel::Errors'
|
82
|
+
# underscore('ActiveModel') # => "active_model"
|
83
|
+
# underscore('ActiveModel::Errors') # => "active_model/errors"
|
86
84
|
#
|
87
85
|
# As a rule of thumb you can think of +underscore+ as the inverse of
|
88
|
-
#
|
86
|
+
# #camelize, though there are cases where that does not hold:
|
89
87
|
#
|
90
|
-
# 'SSLError'
|
88
|
+
# camelize(underscore('SSLError')) # => "SslError"
|
91
89
|
def underscore(camel_cased_word)
|
92
90
|
return camel_cased_word unless camel_cased_word =~ /[A-Z-]|::/
|
93
|
-
word = camel_cased_word.to_s.gsub(
|
94
|
-
word.gsub!(/(?:(?<=([A-Za-z\d]))|\b)(#{inflections.acronym_regex})(?=\b|[^a-z])/) { "#{$1 && '_'}#{$2.downcase}" }
|
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!("-", "_")
|
91
|
+
word = camel_cased_word.to_s.gsub('::'.freeze, '/'.freeze)
|
92
|
+
word.gsub!(/(?:(?<=([A-Za-z\d]))|\b)(#{inflections.acronym_regex})(?=\b|[^a-z])/) { "#{$1 && '_'.freeze }#{$2.downcase}" }
|
93
|
+
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2'.freeze)
|
94
|
+
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2'.freeze)
|
95
|
+
word.tr!("-".freeze, "_".freeze)
|
98
96
|
word.downcase!
|
99
97
|
word
|
100
98
|
end
|
101
99
|
|
102
100
|
# Tweaks an attribute name for display to end users.
|
103
101
|
#
|
104
|
-
# Specifically,
|
102
|
+
# Specifically, performs these transformations:
|
105
103
|
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
#
|
109
|
-
#
|
110
|
-
#
|
111
|
-
#
|
104
|
+
# * Applies human inflection rules to the argument.
|
105
|
+
# * Deletes leading underscores, if any.
|
106
|
+
# * Removes a "_id" suffix if present.
|
107
|
+
# * Replaces underscores with spaces, if any.
|
108
|
+
# * Downcases all words except acronyms.
|
109
|
+
# * Capitalizes the first word.
|
112
110
|
#
|
113
111
|
# The capitalization of the first word can be turned off by setting the
|
114
112
|
# +:capitalize+ option to false (default is true).
|
@@ -127,9 +125,9 @@ module ActiveSupport
|
|
127
125
|
|
128
126
|
inflections.humans.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
|
129
127
|
|
130
|
-
result.sub!(/\A_+/, '')
|
131
|
-
result.sub!(/_id\z/, '')
|
132
|
-
result.tr!('_', ' ')
|
128
|
+
result.sub!(/\A_+/, ''.freeze)
|
129
|
+
result.sub!(/_id\z/, ''.freeze)
|
130
|
+
result.tr!('_'.freeze, ' '.freeze)
|
133
131
|
|
134
132
|
result.gsub!(/([a-z\d]*)/i) do |match|
|
135
133
|
"#{inflections.acronyms[match] || match.downcase}"
|
@@ -148,54 +146,54 @@ module ActiveSupport
|
|
148
146
|
#
|
149
147
|
# +titleize+ is also aliased as +titlecase+.
|
150
148
|
#
|
151
|
-
# 'man from the boondocks'
|
152
|
-
# 'x-men: the last stand'
|
153
|
-
# 'TheManWithoutAPast'
|
154
|
-
# 'raiders_of_the_lost_ark'
|
149
|
+
# titleize('man from the boondocks') # => "Man From The Boondocks"
|
150
|
+
# titleize('x-men: the last stand') # => "X Men: The Last Stand"
|
151
|
+
# titleize('TheManWithoutAPast') # => "The Man Without A Past"
|
152
|
+
# titleize('raiders_of_the_lost_ark') # => "Raiders Of The Lost Ark"
|
155
153
|
def titleize(word)
|
156
154
|
humanize(underscore(word)).gsub(/\b(?<!['’`])[a-z]/) { |match| match.capitalize }
|
157
155
|
end
|
158
156
|
|
159
|
-
#
|
160
|
-
# method uses the
|
157
|
+
# Creates the name of a table like Rails does for models to table names.
|
158
|
+
# This method uses the #pluralize method on the last word in the string.
|
161
159
|
#
|
162
|
-
# 'RawScaledScorer'
|
163
|
-
# '
|
164
|
-
# 'fancyCategory'
|
160
|
+
# tableize('RawScaledScorer') # => "raw_scaled_scorers"
|
161
|
+
# tableize('ham_and_egg') # => "ham_and_eggs"
|
162
|
+
# tableize('fancyCategory') # => "fancy_categories"
|
165
163
|
def tableize(class_name)
|
166
164
|
pluralize(underscore(class_name))
|
167
165
|
end
|
168
166
|
|
169
|
-
#
|
167
|
+
# Creates a class name from a plural table name like Rails does for table
|
170
168
|
# names to models. Note that this returns a string and not a Class (To
|
171
|
-
# convert to an actual class follow +classify+ with
|
169
|
+
# convert to an actual class follow +classify+ with #constantize).
|
172
170
|
#
|
173
|
-
# '
|
174
|
-
# 'posts'
|
171
|
+
# classify('ham_and_eggs') # => "HamAndEgg"
|
172
|
+
# classify('posts') # => "Post"
|
175
173
|
#
|
176
174
|
# Singular names are not handled correctly:
|
177
175
|
#
|
178
|
-
# 'calculus'
|
176
|
+
# classify('calculus') # => "Calculu"
|
179
177
|
def classify(table_name)
|
180
178
|
# strip out any leading schema name
|
181
|
-
camelize(singularize(table_name.to_s.sub(/.*\./, '')))
|
179
|
+
camelize(singularize(table_name.to_s.sub(/.*\./, ''.freeze)))
|
182
180
|
end
|
183
181
|
|
184
182
|
# Replaces underscores with dashes in the string.
|
185
183
|
#
|
186
|
-
# 'puni_puni'
|
184
|
+
# dasherize('puni_puni') # => "puni-puni"
|
187
185
|
def dasherize(underscored_word)
|
188
|
-
underscored_word.tr('_', '-')
|
186
|
+
underscored_word.tr('_'.freeze, '-'.freeze)
|
189
187
|
end
|
190
188
|
|
191
189
|
# Removes the module part from the expression in the string.
|
192
190
|
#
|
193
|
-
# 'ActiveRecord::CoreExtensions::String::Inflections'
|
194
|
-
# 'Inflections'
|
195
|
-
# '::Inflections'
|
196
|
-
# ''
|
191
|
+
# demodulize('ActiveRecord::CoreExtensions::String::Inflections') # => "Inflections"
|
192
|
+
# demodulize('Inflections') # => "Inflections"
|
193
|
+
# demodulize('::Inflections') # => "Inflections"
|
194
|
+
# demodulize('') # => ""
|
197
195
|
#
|
198
|
-
# See also
|
196
|
+
# See also #deconstantize.
|
199
197
|
def demodulize(path)
|
200
198
|
path = path.to_s
|
201
199
|
if i = path.rindex('::')
|
@@ -207,13 +205,13 @@ module ActiveSupport
|
|
207
205
|
|
208
206
|
# Removes the rightmost segment from the constant expression in the string.
|
209
207
|
#
|
210
|
-
# 'Net::HTTP'
|
211
|
-
# '::Net::HTTP'
|
212
|
-
# 'String'
|
213
|
-
# '::String'
|
214
|
-
# ''
|
208
|
+
# deconstantize('Net::HTTP') # => "Net"
|
209
|
+
# deconstantize('::Net::HTTP') # => "::Net"
|
210
|
+
# deconstantize('String') # => ""
|
211
|
+
# deconstantize('::String') # => ""
|
212
|
+
# deconstantize('') # => ""
|
215
213
|
#
|
216
|
-
# See also
|
214
|
+
# See also #demodulize.
|
217
215
|
def deconstantize(path)
|
218
216
|
path.to_s[0, path.rindex('::') || 0] # implementation based on the one in facets' Module#spacename
|
219
217
|
end
|
@@ -222,17 +220,17 @@ module ActiveSupport
|
|
222
220
|
# +separate_class_name_and_id_with_underscore+ sets whether
|
223
221
|
# the method should put '_' between the name and 'id'.
|
224
222
|
#
|
225
|
-
# 'Message'
|
226
|
-
# 'Message'
|
227
|
-
# 'Admin::Post'
|
223
|
+
# foreign_key('Message') # => "message_id"
|
224
|
+
# foreign_key('Message', false) # => "messageid"
|
225
|
+
# foreign_key('Admin::Post') # => "post_id"
|
228
226
|
def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
|
229
227
|
underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id")
|
230
228
|
end
|
231
229
|
|
232
230
|
# Tries to find a constant with the name specified in the argument string.
|
233
231
|
#
|
234
|
-
# 'Module'.constantize
|
235
|
-
# '
|
232
|
+
# 'Module'.constantize # => Module
|
233
|
+
# 'Foo::Bar'.constantize # => Foo::Bar
|
236
234
|
#
|
237
235
|
# The name is assumed to be the one of a top-level constant, no matter
|
238
236
|
# whether it starts with "::" or not. No lexical context is taken into
|
@@ -248,7 +246,7 @@ module ActiveSupport
|
|
248
246
|
# NameError is raised when the name is not in CamelCase or the constant is
|
249
247
|
# unknown.
|
250
248
|
def constantize(camel_cased_word)
|
251
|
-
names = camel_cased_word.split('::')
|
249
|
+
names = camel_cased_word.split('::'.freeze)
|
252
250
|
|
253
251
|
# Trigger a built-in NameError exception including the ill-formed constant in the message.
|
254
252
|
Object.const_get(camel_cased_word) if names.empty?
|
@@ -280,8 +278,8 @@ module ActiveSupport
|
|
280
278
|
|
281
279
|
# Tries to find a constant with the name specified in the argument string.
|
282
280
|
#
|
283
|
-
# 'Module'
|
284
|
-
# '
|
281
|
+
# safe_constantize('Module') # => Module
|
282
|
+
# safe_constantize('Foo::Bar') # => Foo::Bar
|
285
283
|
#
|
286
284
|
# The name is assumed to be the one of a top-level constant, no matter
|
287
285
|
# whether it starts with "::" or not. No lexical context is taken into
|
@@ -290,16 +288,16 @@ module ActiveSupport
|
|
290
288
|
# C = 'outside'
|
291
289
|
# module M
|
292
290
|
# C = 'inside'
|
293
|
-
# C
|
294
|
-
# 'C'
|
291
|
+
# C # => 'inside'
|
292
|
+
# safe_constantize('C') # => 'outside', same as ::C
|
295
293
|
# end
|
296
294
|
#
|
297
295
|
# +nil+ is returned when the name is not in CamelCase or the constant (or
|
298
296
|
# part of it) is unknown.
|
299
297
|
#
|
300
|
-
# 'blargle'
|
301
|
-
# 'UnknownModule'
|
302
|
-
# 'UnknownModule::Foo::Bar'
|
298
|
+
# safe_constantize('blargle') # => nil
|
299
|
+
# safe_constantize('UnknownModule') # => nil
|
300
|
+
# safe_constantize('UnknownModule::Foo::Bar') # => nil
|
303
301
|
def safe_constantize(camel_cased_word)
|
304
302
|
constantize(camel_cased_word)
|
305
303
|
rescue NameError => e
|
@@ -354,7 +352,7 @@ module ActiveSupport
|
|
354
352
|
# const_regexp("Foo::Bar::Baz") # => "Foo(::Bar(::Baz)?)?"
|
355
353
|
# const_regexp("::") # => "::"
|
356
354
|
def const_regexp(camel_cased_word) #:nodoc:
|
357
|
-
parts = camel_cased_word.split("::")
|
355
|
+
parts = camel_cased_word.split("::".freeze)
|
358
356
|
|
359
357
|
return Regexp.escape(camel_cased_word) if parts.blank?
|
360
358
|
|
@@ -372,7 +370,7 @@ module ActiveSupport
|
|
372
370
|
def apply_inflections(word, rules)
|
373
371
|
result = word.to_s.dup
|
374
372
|
|
375
|
-
if word.empty? || inflections.uncountables.
|
373
|
+
if word.empty? || inflections.uncountables.uncountable?(result)
|
376
374
|
result
|
377
375
|
else
|
378
376
|
rules.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
|