aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support/core_ext/module
diff options
context:
space:
mode:
authorXavier Noria <fxn@hashref.com>2011-10-29 18:03:35 -0700
committerXavier Noria <fxn@hashref.com>2011-10-29 18:10:45 -0700
commit11f6795b238172c4a13176062bd38b83285799b7 (patch)
treea70a883974bf91bbecb4ca11d26409243eaf9a30 /activesupport/lib/active_support/core_ext/module
parent8ef1bd9b293678b3d9c07a3f63384781df78b6ad (diff)
downloadrails-11f6795b238172c4a13176062bd38b83285799b7.tar.gz
rails-11f6795b238172c4a13176062bd38b83285799b7.tar.bz2
rails-11f6795b238172c4a13176062bd38b83285799b7.zip
defines Module#qualified_const_(defined?|get|set) and String#deconstantize
This commit also implements a faster version of #demodulize I was unable to isolate with git add --patch. Not a big fan of the name #deconstantize. It complements #demodulize getting rid of the rightmost constant, hence the name, but it is unrelated to the well-known #constantize. So unsure. Could not come with anything better, please feel free to rename.
Diffstat (limited to 'activesupport/lib/active_support/core_ext/module')
-rw-r--r--activesupport/lib/active_support/core_ext/module/qualified_const.rb64
1 files changed, 64 insertions, 0 deletions
diff --git a/activesupport/lib/active_support/core_ext/module/qualified_const.rb b/activesupport/lib/active_support/core_ext/module/qualified_const.rb
new file mode 100644
index 0000000000..d1a0ee2f83
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/module/qualified_const.rb
@@ -0,0 +1,64 @@
+require 'active_support/core_ext/string/inflections'
+
+#--
+# Allows code reuse in the methods below without polluting Module.
+#++
+module QualifiedConstUtils
+ def self.raise_if_absolute(path)
+ raise NameError, "wrong constant name #$&" if path =~ /\A::[^:]+/
+ end
+
+ def self.names(path)
+ path.split('::')
+ end
+end
+
+##
+# Extends the API for constants to be able to deal with qualified names. Arguments
+# are assumed to be relative to the receiver.
+#
+#--
+# Qualified names are required to be relative because we are extending existing
+# methods that expect constant names, ie, relative paths of length 1. For example,
+# Object.const_get("::String") raises NameError and so does qualified_const_get.
+#++
+class Module
+ if method(:const_defined?).arity == 1
+ def qualified_const_defined?(path)
+ QualifiedConstUtils.raise_if_absolute(path)
+
+ QualifiedConstUtils.names(path).inject(self) do |mod, name|
+ return unless mod.const_defined?(name)
+ mod.const_get(name)
+ end
+ return true
+ end
+ else
+ def qualified_const_defined?(path, search_parents=true)
+ QualifiedConstUtils.raise_if_absolute(path)
+
+ QualifiedConstUtils.names(path).inject(self) do |mod, name|
+ return unless mod.const_defined?(name, search_parents)
+ mod.const_get(name)
+ end
+ return true
+ end
+ end
+
+ def qualified_const_get(path)
+ QualifiedConstUtils.raise_if_absolute(path)
+
+ QualifiedConstUtils.names(path).inject(self) do |mod, name|
+ mod.const_get(name)
+ end
+ end
+
+ def qualified_const_set(path, value)
+ QualifiedConstUtils.raise_if_absolute(path)
+
+ const_name = path.demodulize
+ mod_name = path.deconstantize
+ mod = mod_name.empty? ? self : qualified_const_get(mod_name)
+ mod.const_set(const_name, value)
+ end
+end