aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support/inflector/methods.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport/lib/active_support/inflector/methods.rb')
-rw-r--r--activesupport/lib/active_support/inflector/methods.rb46
1 files changed, 46 insertions, 0 deletions
diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb
index 423b5abd20..934529d496 100644
--- a/activesupport/lib/active_support/inflector/methods.rb
+++ b/activesupport/lib/active_support/inflector/methods.rb
@@ -224,6 +224,39 @@ module ActiveSupport
end
end
+ # Tries to find a constant with the name specified in the argument string:
+ #
+ # "Module".safe_constantize # => Module
+ # "Test::Unit".safe_constantize # => Test::Unit
+ #
+ # The name is assumed to be the one of a top-level constant, no matter whether
+ # it starts with "::" or not. No lexical context is taken into account:
+ #
+ # C = 'outside'
+ # module M
+ # C = 'inside'
+ # C # => 'inside'
+ # "C".safe_constantize # => 'outside', same as ::C
+ # end
+ #
+ # nil is returned when the name is not in CamelCase or the constant (or part of it) is
+ # unknown.
+ #
+ # "blargle".safe_constantize # => nil
+ # "UnknownModule".safe_constantize # => nil
+ # "UnknownModule::Foo::Bar".safe_constantize # => nil
+ #
+ def safe_constantize(camel_cased_word)
+ begin
+ constantize(camel_cased_word)
+ rescue NameError => e
+ raise unless e.message =~ /uninitialized constant #{const_regexp(camel_cased_word)}$/ ||
+ e.name.to_s == camel_cased_word.to_s
+ rescue ArgumentError => e
+ raise unless e.message =~ /not missing constant #{const_regexp(camel_cased_word)}\!$/
+ end
+ end
+
# Turns a number into an ordinal string used to denote the position in an
# ordered sequence such as 1st, 2nd, 3rd, 4th.
#
@@ -246,5 +279,18 @@ module ActiveSupport
end
end
end
+
+ private
+
+ # Mount a regular expression that will match part by part of the constant.
+ # For instance, Foo::Bar::Baz will generate Foo(::Bar(::Baz)?)?
+ def const_regexp(camel_cased_word) #:nodoc:
+ parts = camel_cased_word.split("::")
+ last = parts.pop
+
+ parts.reverse.inject(last) do |acc, part|
+ part.empty? ? acc : "#{part}(::#{acc})?"
+ end
+ end
end
end