mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* object.c (rb_mod_const_get): const_get accepts qualified constant
strings. e.g. Object.const_get("Foo::Bar::Baz") [ruby-core:41404] * test/ruby/test_module.rb: tests for new behavior git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37335 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
8ee4f0ad80
commit
82af182e74
4 changed files with 123 additions and 23 deletions
|
@ -1,3 +1,10 @@
|
||||||
|
Sat Oct 27 06:28:33 2012 Aaron Patterson <aaron@tenderlovemaking.com>
|
||||||
|
|
||||||
|
* object.c (rb_mod_const_get): const_get accepts qualified constant
|
||||||
|
strings. e.g. Object.const_get("Foo::Bar::Baz") [ruby-core:41404]
|
||||||
|
|
||||||
|
* test/ruby/test_module.rb: tests for new behavior
|
||||||
|
|
||||||
Fri Oct 26 13:24:20 2012 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
Fri Oct 26 13:24:20 2012 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* parse.y (literal_concat_gen): merge fixed strings across
|
* parse.y (literal_concat_gen): merge fixed strings across
|
||||||
|
|
2
NEWS
2
NEWS
|
@ -66,6 +66,8 @@ with all sufficient information, see the ChangeLog file.
|
||||||
corresponding method in the prepending module.
|
corresponding method in the prepending module.
|
||||||
* extended method:
|
* extended method:
|
||||||
* Module#define_method accepts a UnboundMethod from a Module.
|
* Module#define_method accepts a UnboundMethod from a Module.
|
||||||
|
* Module#const_get accepts a qualified constant string, e.g.
|
||||||
|
Object.const_get("Foo::Bar::Baz")
|
||||||
|
|
||||||
* NilClass
|
* NilClass
|
||||||
* added method:
|
* added method:
|
||||||
|
|
107
object.c
107
object.c
|
@ -1826,33 +1826,11 @@ rb_mod_attr_accessor(int argc, VALUE *argv, VALUE klass)
|
||||||
return Qnil;
|
return Qnil;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* call-seq:
|
|
||||||
* mod.const_get(sym, inherit=true) -> obj
|
|
||||||
*
|
|
||||||
* Checks for a constant with the given name in <i>mod</i>
|
|
||||||
* If +inherit+ is set, the lookup will also search
|
|
||||||
* the ancestors (and +Object+ if <i>mod</i> is a +Module+.)
|
|
||||||
*
|
|
||||||
* The value of the constant is returned if a definition is found,
|
|
||||||
* otherwise a +NameError+ is raised.
|
|
||||||
*
|
|
||||||
* Math.const_get(:PI) #=> 3.14159265358979
|
|
||||||
*/
|
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_mod_const_get(int argc, VALUE *argv, VALUE mod)
|
rb_mod_single_const_get(VALUE mod, VALUE name, VALUE recur)
|
||||||
{
|
{
|
||||||
VALUE name, recur;
|
|
||||||
ID id;
|
ID id;
|
||||||
|
|
||||||
if (argc == 1) {
|
|
||||||
name = argv[0];
|
|
||||||
recur = Qtrue;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
rb_scan_args(argc, argv, "11", &name, &recur);
|
|
||||||
}
|
|
||||||
id = rb_check_id(&name);
|
id = rb_check_id(&name);
|
||||||
if (!id) {
|
if (!id) {
|
||||||
if (!rb_is_const_name(name)) {
|
if (!rb_is_const_name(name)) {
|
||||||
|
@ -1876,6 +1854,89 @@ rb_mod_const_get(int argc, VALUE *argv, VALUE mod)
|
||||||
return RTEST(recur) ? rb_const_get(mod, id) : rb_const_get_at(mod, id);
|
return RTEST(recur) ? rb_const_get(mod, id) : rb_const_get_at(mod, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* mod.const_get(sym, inherit=true) -> obj
|
||||||
|
* mod.const_get(str, inherit=true) -> obj
|
||||||
|
*
|
||||||
|
* Checks for a constant with the given name in <i>mod</i>
|
||||||
|
* If +inherit+ is set, the lookup will also search
|
||||||
|
* the ancestors (and +Object+ if <i>mod</i> is a +Module+.)
|
||||||
|
*
|
||||||
|
* The value of the constant is returned if a definition is found,
|
||||||
|
* otherwise a +NameError+ is raised.
|
||||||
|
*
|
||||||
|
* Math.const_get(:PI) #=> 3.14159265358979
|
||||||
|
*
|
||||||
|
* This method will recursively look up constant names if a namespaced
|
||||||
|
* class name is provided. For example:
|
||||||
|
*
|
||||||
|
* module Foo; class Bar; end end
|
||||||
|
* Object.const_get 'Foo::Bar'
|
||||||
|
*
|
||||||
|
* The +inherit+ flag is respected on each lookup. For example:
|
||||||
|
*
|
||||||
|
* module Foo
|
||||||
|
* class Bar
|
||||||
|
* VAL = 10
|
||||||
|
* end
|
||||||
|
*
|
||||||
|
* class Baz < Bar; end
|
||||||
|
* end
|
||||||
|
*
|
||||||
|
* Object.const_get 'Foo::Baz::VAL' # => 10
|
||||||
|
* Object.const_get 'Foo::Baz::VAL', false # => NameError
|
||||||
|
*/
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_mod_const_get(int argc, VALUE *argv, VALUE mod)
|
||||||
|
{
|
||||||
|
VALUE name, recur;
|
||||||
|
rb_encoding *enc;
|
||||||
|
const char *pbeg, *p, *path;
|
||||||
|
ID id;
|
||||||
|
|
||||||
|
if (argc == 1) {
|
||||||
|
name = argv[0];
|
||||||
|
recur = Qtrue;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rb_scan_args(argc, argv, "11", &name, &recur);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SYMBOL_P(name)) {
|
||||||
|
name = rb_sym_to_s(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
enc = rb_enc_get(name);
|
||||||
|
path = RSTRING_PTR(name);
|
||||||
|
|
||||||
|
if (!rb_enc_asciicompat(enc)) {
|
||||||
|
rb_raise(rb_eArgError, "invalid class path encoding (non ASCII)");
|
||||||
|
}
|
||||||
|
|
||||||
|
pbeg = p = path;
|
||||||
|
while (*p) {
|
||||||
|
while (*p && *p != ':') p++;
|
||||||
|
id = rb_intern3(pbeg, p-pbeg, enc);
|
||||||
|
if (p[0] == ':') {
|
||||||
|
if (p[1] != ':') {
|
||||||
|
rb_raise(rb_eArgError, "undefined class/module %.*s", (int)(p-path), path);
|
||||||
|
}
|
||||||
|
p += 2;
|
||||||
|
pbeg = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!RB_TYPE_P(mod, T_MODULE) && !RB_TYPE_P(mod, T_CLASS)) {
|
||||||
|
rb_raise(rb_eTypeError, "%s does not refer to class/module", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
mod = rb_mod_single_const_get(mod, ID2SYM(id), recur);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* mod.const_set(sym, obj) -> obj
|
* mod.const_set(sym, obj) -> obj
|
||||||
|
|
|
@ -245,6 +245,36 @@ class TestModule < Test::Unit::TestCase
|
||||||
assert_equal(Math::PI, Math.const_get(:PI))
|
assert_equal(Math::PI, Math.const_get(:PI))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_nested_get
|
||||||
|
assert_equal Other, Object.const_get([self.class, Other].join('::'))
|
||||||
|
assert_equal User::USER, self.class.const_get([User, 'USER'].join('::'))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_nested_get_symbol
|
||||||
|
const = [self.class, Other].join('::').to_sym
|
||||||
|
|
||||||
|
assert_equal Other, Object.const_get(const)
|
||||||
|
assert_equal User::USER, self.class.const_get([User, 'USER'].join('::'))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_nested_get_const_missing
|
||||||
|
classes = []
|
||||||
|
klass = Class.new {
|
||||||
|
define_singleton_method(:const_missing) { |name|
|
||||||
|
classes << name
|
||||||
|
klass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
klass.const_get("Foo::Bar::Baz")
|
||||||
|
assert_equal [:Foo, :Bar, :Baz], classes
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_nested_bad_class
|
||||||
|
assert_raises(TypeError) do
|
||||||
|
self.class.const_get([User, 'USER', 'Foo'].join('::'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_const_set
|
def test_const_set
|
||||||
assert(!Other.const_defined?(:KOALA))
|
assert(!Other.const_defined?(:KOALA))
|
||||||
Other.const_set(:KOALA, 99)
|
Other.const_set(:KOALA, 99)
|
||||||
|
|
Loading…
Add table
Reference in a new issue