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.

Files changed (174) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +309 -485
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -3
  5. data/lib/active_support.rb +8 -15
  6. data/lib/active_support/array_inquirer.rb +44 -0
  7. data/lib/active_support/backtrace_cleaner.rb +1 -1
  8. data/lib/active_support/cache.rb +59 -72
  9. data/lib/active_support/cache/file_store.rb +27 -19
  10. data/lib/active_support/cache/mem_cache_store.rb +71 -60
  11. data/lib/active_support/cache/memory_store.rb +16 -21
  12. data/lib/active_support/cache/null_store.rb +1 -4
  13. data/lib/active_support/cache/strategy/local_cache.rb +31 -20
  14. data/lib/active_support/callbacks.rb +107 -111
  15. data/lib/active_support/concern.rb +1 -1
  16. data/lib/active_support/concurrency/latch.rb +7 -15
  17. data/lib/active_support/concurrency/share_lock.rb +142 -0
  18. data/lib/active_support/configurable.rb +1 -0
  19. data/lib/active_support/core_ext.rb +2 -1
  20. data/lib/active_support/core_ext/array.rb +1 -0
  21. data/lib/active_support/core_ext/array/access.rb +13 -1
  22. data/lib/active_support/core_ext/array/conversions.rb +6 -4
  23. data/lib/active_support/core_ext/array/inquiry.rb +17 -0
  24. data/lib/active_support/core_ext/array/wrap.rb +5 -4
  25. data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -10
  26. data/lib/active_support/core_ext/class.rb +0 -1
  27. data/lib/active_support/core_ext/class/attribute.rb +10 -9
  28. data/lib/active_support/core_ext/class/subclasses.rb +5 -2
  29. data/lib/active_support/core_ext/date.rb +1 -1
  30. data/lib/active_support/core_ext/date/blank.rb +12 -0
  31. data/lib/active_support/core_ext/date/calculations.rb +1 -1
  32. data/lib/active_support/core_ext/date/conversions.rb +3 -3
  33. data/lib/active_support/core_ext/date_and_time/calculations.rb +93 -27
  34. data/lib/active_support/core_ext/date_and_time/zones.rb +1 -2
  35. data/lib/active_support/core_ext/date_time.rb +1 -1
  36. data/lib/active_support/core_ext/date_time/blank.rb +12 -0
  37. data/lib/active_support/core_ext/date_time/calculations.rb +7 -23
  38. data/lib/active_support/core_ext/date_time/conversions.rb +2 -0
  39. data/lib/active_support/core_ext/enumerable.rb +27 -17
  40. data/lib/active_support/core_ext/file/atomic.rb +30 -25
  41. data/lib/active_support/core_ext/hash/compact.rb +15 -19
  42. data/lib/active_support/core_ext/hash/conversions.rb +21 -2
  43. data/lib/active_support/core_ext/hash/deep_merge.rb +1 -1
  44. data/lib/active_support/core_ext/hash/except.rb +9 -8
  45. data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -1
  46. data/lib/active_support/core_ext/hash/keys.rb +22 -18
  47. data/lib/active_support/core_ext/hash/slice.rb +1 -1
  48. data/lib/active_support/core_ext/hash/transform_values.rb +13 -7
  49. data/lib/active_support/core_ext/integer/time.rb +1 -1
  50. data/lib/active_support/core_ext/kernel.rb +0 -1
  51. data/lib/active_support/core_ext/kernel/debugger.rb +3 -10
  52. data/lib/active_support/core_ext/kernel/reporting.rb +0 -84
  53. data/lib/active_support/core_ext/load_error.rb +4 -2
  54. data/lib/active_support/core_ext/marshal.rb +8 -13
  55. data/lib/active_support/core_ext/module.rb +1 -0
  56. data/lib/active_support/core_ext/module/aliasing.rb +6 -1
  57. data/lib/active_support/core_ext/module/anonymous.rb +10 -1
  58. data/lib/active_support/core_ext/module/attr_internal.rb +2 -5
  59. data/lib/active_support/core_ext/module/attribute_accessors.rb +7 -7
  60. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +141 -0
  61. data/lib/active_support/core_ext/module/concerning.rb +4 -4
  62. data/lib/active_support/core_ext/module/delegation.rb +7 -14
  63. data/lib/active_support/core_ext/module/method_transplanting.rb +3 -13
  64. data/lib/active_support/core_ext/module/qualified_const.rb +30 -12
  65. data/lib/active_support/core_ext/module/remove_method.rb +23 -0
  66. data/lib/active_support/core_ext/name_error.rb +15 -2
  67. data/lib/active_support/core_ext/numeric.rb +1 -0
  68. data/lib/active_support/core_ext/numeric/bytes.rb +20 -0
  69. data/lib/active_support/core_ext/numeric/conversions.rb +12 -23
  70. data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
  71. data/lib/active_support/core_ext/numeric/time.rb +20 -0
  72. data/lib/active_support/core_ext/object.rb +0 -1
  73. data/lib/active_support/core_ext/object/blank.rb +11 -2
  74. data/lib/active_support/core_ext/object/deep_dup.rb +10 -3
  75. data/lib/active_support/core_ext/object/duplicable.rb +39 -70
  76. data/lib/active_support/core_ext/object/inclusion.rb +2 -2
  77. data/lib/active_support/core_ext/object/instance_variables.rb +1 -1
  78. data/lib/active_support/core_ext/object/json.rb +9 -7
  79. data/lib/active_support/core_ext/object/to_query.rb +1 -1
  80. data/lib/active_support/core_ext/object/try.rb +67 -21
  81. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  82. data/lib/active_support/core_ext/range/conversions.rb +18 -6
  83. data/lib/active_support/core_ext/range/each.rb +16 -18
  84. data/lib/active_support/core_ext/range/include_range.rb +20 -20
  85. data/lib/active_support/core_ext/securerandom.rb +23 -0
  86. data/lib/active_support/core_ext/string/access.rb +1 -1
  87. data/lib/active_support/core_ext/string/behavior.rb +1 -1
  88. data/lib/active_support/core_ext/string/conversions.rb +2 -2
  89. data/lib/active_support/core_ext/string/filters.rb +1 -2
  90. data/lib/active_support/core_ext/string/inflections.rb +23 -5
  91. data/lib/active_support/core_ext/string/multibyte.rb +11 -7
  92. data/lib/active_support/core_ext/string/output_safety.rb +8 -9
  93. data/lib/active_support/core_ext/string/strip.rb +3 -6
  94. data/lib/active_support/core_ext/struct.rb +3 -6
  95. data/lib/active_support/core_ext/time.rb +0 -2
  96. data/lib/active_support/core_ext/time/calculations.rb +18 -16
  97. data/lib/active_support/core_ext/time/conversions.rb +4 -2
  98. data/lib/active_support/core_ext/time/marshal.rb +2 -29
  99. data/lib/active_support/core_ext/time/zones.rb +19 -3
  100. data/lib/active_support/core_ext/uri.rb +1 -3
  101. data/lib/active_support/dependencies.rb +79 -44
  102. data/lib/active_support/dependencies/interlock.rb +47 -0
  103. data/lib/active_support/deprecation/behaviors.rb +12 -0
  104. data/lib/active_support/deprecation/method_wrappers.rb +42 -16
  105. data/lib/active_support/deprecation/proxy_wrappers.rb +47 -24
  106. data/lib/active_support/deprecation/reporting.rb +13 -2
  107. data/lib/active_support/duration.rb +5 -8
  108. data/lib/active_support/evented_file_update_checker.rb +150 -0
  109. data/lib/active_support/file_update_checker.rb +1 -1
  110. data/lib/active_support/gem_version.rb +5 -5
  111. data/lib/active_support/hash_with_indifferent_access.rb +15 -17
  112. data/lib/active_support/i18n_railtie.rb +25 -4
  113. data/lib/active_support/inflector/inflections.rb +36 -5
  114. data/lib/active_support/inflector/methods.rb +87 -89
  115. data/lib/active_support/inflector/transliterate.rb +36 -21
  116. data/lib/active_support/json/decoding.rb +2 -8
  117. data/lib/active_support/json/encoding.rb +0 -50
  118. data/lib/active_support/key_generator.rb +4 -4
  119. data/lib/active_support/log_subscriber.rb +1 -1
  120. data/lib/active_support/log_subscriber/test_helper.rb +3 -3
  121. data/lib/active_support/logger.rb +4 -52
  122. data/lib/active_support/logger_silence.rb +3 -5
  123. data/lib/active_support/message_encryptor.rb +4 -11
  124. data/lib/active_support/message_verifier.rb +64 -8
  125. data/lib/active_support/multibyte/chars.rb +12 -3
  126. data/lib/active_support/multibyte/unicode.rb +6 -8
  127. data/lib/active_support/notifications.rb +2 -2
  128. data/lib/active_support/notifications/fanout.rb +5 -5
  129. data/lib/active_support/notifications/instrumenter.rb +19 -2
  130. data/lib/active_support/number_helper.rb +21 -15
  131. data/lib/active_support/number_helper/number_to_currency_converter.rb +4 -4
  132. data/lib/active_support/number_helper/number_to_delimited_converter.rb +7 -2
  133. data/lib/active_support/number_helper/number_to_human_converter.rb +6 -4
  134. data/lib/active_support/number_helper/number_to_human_size_converter.rb +5 -1
  135. data/lib/active_support/number_helper/number_to_percentage_converter.rb +1 -1
  136. data/lib/active_support/number_helper/number_to_rounded_converter.rb +28 -25
  137. data/lib/active_support/ordered_options.rb +15 -1
  138. data/lib/active_support/per_thread_registry.rb +3 -0
  139. data/lib/active_support/rails.rb +2 -2
  140. data/lib/active_support/railtie.rb +6 -1
  141. data/lib/active_support/rescuable.rb +4 -4
  142. data/lib/active_support/security_utils.rb +0 -7
  143. data/lib/active_support/string_inquirer.rb +1 -1
  144. data/lib/active_support/subscriber.rb +5 -10
  145. data/lib/active_support/tagged_logging.rb +3 -1
  146. data/lib/active_support/test_case.rb +13 -25
  147. data/lib/active_support/testing/assertions.rb +15 -13
  148. data/lib/active_support/testing/autorun.rb +8 -1
  149. data/lib/active_support/testing/composite_filter.rb +54 -0
  150. data/lib/active_support/testing/deprecation.rb +9 -8
  151. data/lib/active_support/testing/file_fixtures.rb +34 -0
  152. data/lib/active_support/testing/isolation.rb +22 -8
  153. data/lib/active_support/testing/method_call_assertions.rb +41 -0
  154. data/lib/active_support/testing/stream.rb +42 -0
  155. data/lib/active_support/testing/time_helpers.rb +6 -6
  156. data/lib/active_support/time_with_zone.rb +135 -53
  157. data/lib/active_support/values/time_zone.rb +80 -46
  158. data/lib/active_support/values/unicode_tables.dat +0 -0
  159. data/lib/active_support/xml_mini.rb +15 -30
  160. data/lib/active_support/xml_mini/jdom.rb +1 -1
  161. data/lib/active_support/xml_mini/libxml.rb +5 -3
  162. data/lib/active_support/xml_mini/libxmlsax.rb +4 -1
  163. data/lib/active_support/xml_mini/nokogiri.rb +5 -3
  164. data/lib/active_support/xml_mini/nokogirisax.rb +3 -1
  165. data/lib/active_support/xml_mini/rexml.rb +3 -1
  166. metadata +57 -21
  167. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -16
  168. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  169. data/lib/active_support/core_ext/date_and_time/compatibility.rb +0 -15
  170. data/lib/active_support/core_ext/date_time/compatibility.rb +0 -16
  171. data/lib/active_support/core_ext/object/itself.rb +0 -15
  172. data/lib/active_support/core_ext/thread.rb +0 -86
  173. data/lib/active_support/core_ext/time/compatibility.rb +0 -14
  174. 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 = 4
9
- MINOR = 2
10
- TINY = 11
11
- PRE = "3"
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
- hash = hash.to_hash
77
- new(hash).tap do |new_hash|
78
- new_hash.default = hash.default
79
- new_hash.default_proc = hash.default_proc if hash.default_proc
80
- end
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 +'key'+.
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.new_from_hash_copying_default(other_hash))
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.new_from_hash_copying_default(other_hash))
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
- app.config.i18n.load_path.unshift(*value)
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
- reloader = ActiveSupport::FileUpdateChecker.new(I18n.load_path.dup){ I18n.reload! }
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 { reloader.execute_if_updated }
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.send(:include, I18n::Backend::Fallbacks)
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 'thread_safe'
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__ = ThreadSafe::Cache.new
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 = [], [], [], [], {}, /(?=a)b/
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 += words.flatten.map(&:downcase)
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'.pluralize # => "posts"
26
- # 'octopus'.pluralize # => "octopi"
27
- # 'sheep'.pluralize # => "sheep"
28
- # 'words'.pluralize # => "words"
29
- # 'CamelOctopus'.pluralize # => "CamelOctopi"
30
- # 'ley'.pluralize(:es) # => "leyes"
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 +pluralize+, returns the singular form of a word in a
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'.singularize # => "post"
43
- # 'octopi'.singularize # => "octopus"
44
- # 'sheep'.singularize # => "sheep"
45
- # 'word'.singularize # => "word"
46
- # 'CamelOctopi'.singularize # => "CamelOctopus"
47
- # 'leyes'.singularize(:es) # => "ley"
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
- # By default, +camelize+ converts strings to UpperCamelCase. If the argument
53
- # to +camelize+ is set to <tt>:lower</tt> then +camelize+ produces
50
+ # Converts strings to UpperCamelCase.
51
+ # If the +uppercase_first_letter+ parameter is set to false, then produces
54
52
  # lowerCamelCase.
55
53
  #
56
- # +camelize+ will also convert '/' to '::' which is useful for converting
54
+ # Also converts '/' to '::' which is useful for converting
57
55
  # paths to namespaces.
58
56
  #
59
- # 'active_model'.camelize # => "ActiveModel"
60
- # 'active_model'.camelize(:lower) # => "activeModel"
61
- # 'active_model/errors'.camelize # => "ActiveModel::Errors"
62
- # 'active_model/errors'.camelize(:lower) # => "activeModel::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
- # +underscore+, though there are cases where that does not hold:
63
+ # #underscore, though there are cases where that does not hold:
66
64
  #
67
- # 'SSLError'.underscore.camelize # => "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[$&] || $&.capitalize }
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)/) { $&.downcase }
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'.underscore # => "active_model"
85
- # 'ActiveModel::Errors'.underscore # => "active_model/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
- # +camelize+, though there are cases where that does not hold:
86
+ # #camelize, though there are cases where that does not hold:
89
87
  #
90
- # 'SSLError'.underscore.camelize # => "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, +humanize+ performs these transformations:
102
+ # Specifically, performs these transformations:
105
103
  #
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.
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'.titleize # => "Man From The Boondocks"
152
- # 'x-men: the last stand'.titleize # => "X Men: The Last Stand"
153
- # 'TheManWithoutAPast'.titleize # => "The Man Without A Past"
154
- # 'raiders_of_the_lost_ark'.titleize # => "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
- # Create the name of a table like Rails does for models to table names. This
160
- # method uses the +pluralize+ method on the last word in the string.
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'.tableize # => "raw_scaled_scorers"
163
- # 'egg_and_ham'.tableize # => "egg_and_hams"
164
- # 'fancyCategory'.tableize # => "fancy_categories"
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
- # Create a class name from a plural table name like Rails does for table
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 +constantize+).
169
+ # convert to an actual class follow +classify+ with #constantize).
172
170
  #
173
- # 'egg_and_hams'.classify # => "EggAndHam"
174
- # 'posts'.classify # => "Post"
171
+ # classify('ham_and_eggs') # => "HamAndEgg"
172
+ # classify('posts') # => "Post"
175
173
  #
176
174
  # Singular names are not handled correctly:
177
175
  #
178
- # 'calculus'.classify # => "Calculu"
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'.dasherize # => "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'.demodulize # => "Inflections"
194
- # 'Inflections'.demodulize # => "Inflections"
195
- # '::Inflections'.demodulize # => "Inflections"
196
- # ''.demodulize # => ""
191
+ # demodulize('ActiveRecord::CoreExtensions::String::Inflections') # => "Inflections"
192
+ # demodulize('Inflections') # => "Inflections"
193
+ # demodulize('::Inflections') # => "Inflections"
194
+ # demodulize('') # => ""
197
195
  #
198
- # See also +deconstantize+.
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'.deconstantize # => "Net"
211
- # '::Net::HTTP'.deconstantize # => "::Net"
212
- # 'String'.deconstantize # => ""
213
- # '::String'.deconstantize # => ""
214
- # ''.deconstantize # => ""
208
+ # deconstantize('Net::HTTP') # => "Net"
209
+ # deconstantize('::Net::HTTP') # => "::Net"
210
+ # deconstantize('String') # => ""
211
+ # deconstantize('::String') # => ""
212
+ # deconstantize('') # => ""
215
213
  #
216
- # See also +demodulize+.
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'.foreign_key # => "message_id"
226
- # 'Message'.foreign_key(false) # => "messageid"
227
- # 'Admin::Post'.foreign_key # => "post_id"
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 # => Module
235
- # 'Test::Unit'.constantize # => Test::Unit
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'.safe_constantize # => Module
284
- # 'Test::Unit'.safe_constantize # => Test::Unit
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 # => 'inside'
294
- # 'C'.safe_constantize # => 'outside', same as ::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'.safe_constantize # => nil
301
- # 'UnknownModule'.safe_constantize # => nil
302
- # 'UnknownModule::Foo::Bar'.safe_constantize # => nil
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.include?(result.downcase[/\b\w+\Z/])
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) }