Project

General

Profile

Feature #5690 ยป p2c.diff

tenderlovemaking (Aaron Patterson), 10/24/2012 02:40 AM

View differences:

object.c
1826 1826
    return Qnil;
1827 1827
}
1828 1828

  
1829
static VALUE
1830
rb_mod_single_const_get(VALUE mod, VALUE name, VALUE recur)
1831
{
1832
    ID id;
1833

  
1834
    id = rb_check_id(&name);
1835
    if (!id) {
1836
	if (!rb_is_const_name(name)) {
1837
	    rb_name_error_str(name, "wrong constant name %s", RSTRING_PTR(name));
1838
	}
1839
	else if (!rb_method_basic_definition_p(CLASS_OF(mod), id_const_missing)) {
1840
	    id = rb_to_id(name);
1841
	}
1842
	else if (mod && rb_class_real(mod) != rb_cObject) {
1843
	    rb_name_error_str(name, "uninitialized constant %s::%s",
1844
			      rb_class2name(mod),
1845
			      RSTRING_PTR(name));
1846
	}
1847
	else {
1848
	    rb_name_error_str(name, "uninitialized constant %s", RSTRING_PTR(name));
1849
	}
1850
    }
1851
    if (!rb_is_const_id(id)) {
1852
	rb_name_error(id, "wrong constant name %s", rb_id2name(id));
1853
    }
1854
    return RTEST(recur) ? rb_const_get(mod, id) : rb_const_get_at(mod, id);
1855
}
1856

  
1829 1857
/*
1830 1858
 *  call-seq:
1831 1859
 *     mod.const_get(sym, inherit=true)    -> obj
1860
 *     mod.const_get(str, inherit=true)    -> obj
1832 1861
 *
1833 1862
 *  Checks for a constant with the given name in <i>mod</i>
1834 1863
 *  If +inherit+ is set, the lookup will also search
......
1838 1867
 *  otherwise a +NameError+ is raised.
1839 1868
 *
1840 1869
 *     Math.const_get(:PI)   #=> 3.14159265358979
1870
 *
1871
 *  This method will recursively look up constant names if a namespaced
1872
 *  class name is provided.  For example:
1873
 *
1874
 *     module Foo; class Bar; end end
1875
 *     Object.const_get 'Foo::Bar'
1876
 *
1877
 *  The +inherit+ flag is respected on each lookup.  For example:
1878
 *
1879
 *     module Foo
1880
 *       class Bar
1881
 *         VAL = 10
1882
 *       end
1883
 *
1884
 *       class Baz < Bar; end
1885
 *     end
1886
 *
1887
 *     Object.const_get 'Foo::Baz::VAL'         # => 10
1888
 *     Object.const_get 'Foo::Baz::VAL', false  # => NameError
1841 1889
 */
1842 1890

  
1843 1891
static VALUE
1844 1892
rb_mod_const_get(int argc, VALUE *argv, VALUE mod)
1845 1893
{
1846 1894
    VALUE name, recur;
1895
    rb_encoding *enc;
1896
    const char *pbeg, *p, *path;
1847 1897
    ID id;
1848 1898

  
1849 1899
    if (argc == 1) {
......
1853 1903
    else {
1854 1904
	rb_scan_args(argc, argv, "11", &name, &recur);
1855 1905
    }
1856
    id = rb_check_id(&name);
1857
    if (!id) {
1858
	if (!rb_is_const_name(name)) {
1859
	    rb_name_error_str(name, "wrong constant name %s", RSTRING_PTR(name));
1860
	}
1861
	else if (!rb_method_basic_definition_p(CLASS_OF(mod), id_const_missing)) {
1862
	    id = rb_to_id(name);
1863
	}
1864
	else if (mod && rb_class_real(mod) != rb_cObject) {
1865
	    rb_name_error_str(name, "uninitialized constant %s::%s",
1866
			      rb_class2name(mod),
1867
			      RSTRING_PTR(name));
1906

  
1907
    if (SYMBOL_P(name)) {
1908
      name = rb_sym_to_s(name);
1909
    }
1910

  
1911
    enc = rb_enc_get(name);
1912
    path = RSTRING_PTR(name);
1913

  
1914
    if (!rb_enc_asciicompat(enc)) {
1915
	rb_raise(rb_eArgError, "invalid class path encoding (non ASCII)");
1916
    }
1917

  
1918
    pbeg = p = path;
1919
    while (*p) {
1920
	while (*p && *p != ':') p++;
1921
	id = rb_intern3(pbeg, p-pbeg, enc);
1922
	if (p[0] == ':') {
1923
	    if (p[1] != ':') {
1924
              rb_raise(rb_eArgError, "undefined class/module %.*s", (int)(p-path), path);
1925
            }
1926
	    p += 2;
1927
	    pbeg = p;
1868 1928
	}
1869
	else {
1870
	    rb_name_error_str(name, "uninitialized constant %s", RSTRING_PTR(name));
1929

  
1930
	if (!RB_TYPE_P(mod, T_MODULE) && !RB_TYPE_P(mod, T_CLASS)) {
1931
	    rb_raise(rb_eTypeError, "%s does not refer to class/module", path);
1871 1932
	}
1933

  
1934
        mod = rb_mod_single_const_get(mod, ID2SYM(id), recur);
1872 1935
    }
1873
    if (!rb_is_const_id(id)) {
1874
	rb_name_error(id, "wrong constant name %s", rb_id2name(id));
1875
    }
1876
    return RTEST(recur) ? rb_const_get(mod, id) : rb_const_get_at(mod, id);
1936

  
1937
    return mod;
1877 1938
}
1878 1939

  
1879 1940
/*
test/ruby/test_module.rb
245 245
    assert_equal(Math::PI, Math.const_get(:PI))
246 246
  end
247 247

  
248
  def test_nested_get
249
    assert_equal Other, Object.const_get([self.class, Other].join('::'))
250
    assert_equal User::USER, self.class.const_get([User, 'USER'].join('::'))
251
  end
252

  
253
  def test_nested_get_symbol
254
    const = [self.class, Other].join('::').to_sym
255

  
256
    assert_equal Other, Object.const_get(const)
257
    assert_equal User::USER, self.class.const_get([User, 'USER'].join('::'))
258
  end
259

  
260
  def test_nested_get_const_missing
261
    classes = []
262
    klass = Class.new {
263
      define_singleton_method(:const_missing) { |name|
264
	classes << name
265
	klass
266
      }
267
    }
268
    klass.const_get("Foo::Bar::Baz")
269
    assert_equal [:Foo, :Bar, :Baz], classes
270
  end
271

  
272
  def test_nested_bad_class
273
    assert_raises(TypeError) do
274
      self.class.const_get([User, 'USER', 'Foo'].join('::'))
275
    end
276
  end
277

  
248 278
  def test_const_set
249 279
    assert(!Other.const_defined?(:KOALA))
250 280
    Other.const_set(:KOALA, 99)