Get a class from its name

This is how i'm currently getting a class object from a name:

         cname = "A::b::C::D"
         klass = cname.split("::").inject(Kernel) {|a,b| a.const_get(b)}

I think it's pretty elegant, but I'm always happy to hear other ways to do it :wink:
Anyone does this in some other way? (I don't want to eval code...)

regards,

PGP.sig (186 Bytes)

···

--
Rolando Abarca
Phone: +56-9 97851962

I've seen little helper methods for this, but never so elegant. Nice!

···

On Aug 20, 7:16 pm, Rolando Abarca <funkas...@gmail.com> wrote:

This is how i'm currently getting a class object from a name:

         cname = "A::b::C::D"
         klass = cname.split("::").inject(Kernel) {|a,b| a.const_get(b)}

I think it's pretty elegant, but I'm always happy to hear other ways
to do it :wink:
Anyone does this in some other way? (I don't want to eval code...)

regards,
--
Rolando Abarca
Phone: +56-9 97851962

PGP.sig
1KDownload

Hi --

···

On Tue, 21 Aug 2007, Rolando Abarca wrote:

This is how i'm currently getting a class object from a name:

      cname = "A::b::C::D"
      klass = cname.split("::").inject(Kernel) {|a,b| a.const_get(b)}

I think it's pretty elegant, but I'm always happy to hear other ways to do it :wink:
Anyone does this in some other way? (I don't want to eval code...)

I think it's usually done the way you've got it there. It's one of
those things that people write over and over (like map_with_index and
singleton_method), hopefully some day to enter the core as
const_get_deep or something.

David

--
* Books:
   RAILS ROUTING (new! http://www.awprofessional.com/title/0321509242\)
   RUBY FOR RAILS (http://www.manning.com/black\)
* Ruby/Rails training
     & consulting: Ruby Power and Light, LLC (http://www.rubypal.com)

This is how i'm currently getting a class object from a name:

        cname = "A::b::C::D"
        klass = cname.split("::").inject(Kernel) {|a,b| a.const_get(b)}

I think it's pretty elegant, but I'm always happy to hear other ways to do it :wink:
Anyone does this in some other way? (I don't want to eval code...)

I use pretty much the same thing:

class String
   def const_get
     self.split( "::" ).inject( Kernel ) { | parent, child | parent.const_get( child ) }
   end
end

# Example

module A
   class B
     C = 'c'
   end
end

>> "A".const_get
=> A

>> "A::B".const_get
=> A::B

>> "A::b::C".const_get
=> "c"

   ~Wayne

s///g
Wayne E. Seguin
Sr. Systems Architect & Systems Administrator

···

On Aug 20, 2007, at 20:16 , Rolando Abarca wrote:

"A::b::C::D".to_class

It could just be a wrapper for the core method rb_path2class -- which
does the same thing in Ruby C API land.

Blessings,
TwP

···

On 8/20/07, David A. Black <dblack@rubypal.com> wrote:

Hi --

On Tue, 21 Aug 2007, Rolando Abarca wrote:

> This is how i'm currently getting a class object from a name:
>
> cname = "A::b::C::D"
> klass = cname.split("::").inject(Kernel) {|a,b| a.const_get(b)}
>
> I think it's pretty elegant, but I'm always happy to hear other ways to do it
> :wink:
> Anyone does this in some other way? (I don't want to eval code...)

I think it's usually done the way you've got it there. It's one of
those things that people write over and over (like map_with_index and
singleton_method), hopefully some day to enter the core as
const_get_deep or something.

Hi --

···

On Tue, 21 Aug 2007, Tim Pease wrote:

On 8/20/07, David A. Black <dblack@rubypal.com> wrote:

Hi --

On Tue, 21 Aug 2007, Rolando Abarca wrote:

This is how i'm currently getting a class object from a name:

      cname = "A::b::C::D"
      klass = cname.split("::").inject(Kernel) {|a,b| a.const_get(b)}

I think it's pretty elegant, but I'm always happy to hear other ways to do it
:wink:
Anyone does this in some other way? (I don't want to eval code...)

I think it's usually done the way you've got it there. It's one of
those things that people write over and over (like map_with_index and
singleton_method), hopefully some day to enter the core as
const_get_deep or something.

"A::b::C::D".to_class

It could just be a wrapper for the core method rb_path2class -- which
does the same thing in Ruby C API land.

It's a more general-purpose thing, though; it's for any constant, not
just classes. It's really just a variation on const_get, which already
will give you any constant from any existing class/module nesting.

David

--
* Books:
   RAILS ROUTING (new! http://www.awprofessional.com/title/0321509242\)
   RUBY FOR RAILS (http://www.manning.com/black\)
* Ruby/Rails training
     & consulting: Ruby Power and Light, LLC (http://www.rubypal.com)

Hi --

> "A::b::C::D".to_class
>
> It could just be a wrapper for the core method rb_path2class -- which
> does the same thing in Ruby C API land.

It's a more general-purpose thing, though; it's for any constant, not
just classes. It's really just a variation on const_get, which already
will give you any constant from any existing class/module nesting.

Definitively.

Folks, please keep in mind that the proposed solution from the OP's
posting works only in the global context:

irb(main):001:0> module A
irb(main):002:1> module B
irb(main):003:2> module C
irb(main):004:3> end
irb(main):005:2> end
irb(main):006:1> end
=> nil
irb(main):007:0> "A::b::C".split("::").inject(Kernel) {|a,b| a.const_get(b)}
=> A::b::C
irb(main):008:0> module A
irb(main):009:1> p "B::C".split("::").inject(Kernel) {|a,b| a.const_get(b)}
irb(main):010:1> end
NameError: uninitialized constant Kernel::B
        from (irb):9:in `const_get'
        from (irb):9
        from (irb):10:in `inject'
        from (irb):9:in `each'
        from (irb):9:in `inject'
        from (irb):9
irb(main):011:0> module A
irb(main):012:1> p "B::C".split("::").inject(self) {|a,b| a.const_get(b)}
irb(main):013:1> end
=> nil

There needs to be at least a bit more logic to take care of nested
scopes and constants with leading "::". Having said that it's probably
wise to put the method in class Module, like:

class Module
  def deref(name)
    parts = name.split "::"
    start = self

    if parts.first == ""
      # start with global scope
      start = Kernel
      parts.shift
    end

    parts.inject(start) {|a,b| a.const_get(b)}
  end
end

class Object
  def deref(name)
    self.class.deref(name)
  end
end

irb(main):021:0> module A
irb(main):022:1> module B
irb(main):023:2> module C
irb(main):024:3> end
irb(main):025:2> end
irb(main):026:1> end
=> nil
irb(main):027:0> deref "A::b::C"
=> A::b::C
irb(main):028:0> module A
irb(main):029:1> p deref("B::C")
irb(main):030:1> p deref("::a::B")
irb(main):031:1> end
=> nil

Kind regards

robert

···

2007/8/21, David A. Black <dblack@rubypal.com>:

On Tue, 21 Aug 2007, Tim Pease wrote:

        from :0
A::b::C
A::b::C
A::B

Definitively.

Folks, please keep in mind that the proposed solution from the OP's
posting works only in the global context:

Ok... I get your point. It's not a general dereferencer, i mean, it doesn't take the current scope and figure it outs the name from there, it always assume the string is the full path... Maybe what you propose could be the general solution to the deref problem :slight_smile:

robert

regards,

PGP.sig (186 Bytes)

···

On Aug 21, 2007, at 10:41 AM, Robert Klemme wrote:
--
Rolando Abarca
Phone: +56-9 97851962