Reputation: 497
I often need to get the pure class name of an object, as code below:
class Foo
class Bar
end
end
obj = Foo::Bar.new
puts obj.class.name # It shows "Foo::Bar", while what I want is just "Bar"
I know it can be done by obj.class.name.split('::').last, but, shouldn't be there a method just return "Bar" ?
Upvotes: 4
Views: 1391
Reputation: 3959
based on thomax answer i've researched it a bit...
require 'benchmark'
class String
def demodulize
self[(rindex('::') || -2) + 2..-1]
end
def split_last
split('::').last
end
def demodulize_vs_split_last n = 5000000
Benchmark.bm(10) do |x|
x.report('split_last') { n.times { split_last } }
x.report('demodulize') { n.times { demodulize } }
end
end
end
and got this:
> 'Core::String'.demodulize_vs_split_last
user system total real
split_last 1.960688 0.008501 1.969189 ( 1.983187)
demodulize 1.807694 0.005815 1.813509 ( 1.826771)
for short strings it mostly similar
> 'Core::Exten::sions::String::Inf::lect::ions'.demodulize_vs_split_last
user system total real
split_last 4.386797 0.024131 4.410928 ( 4.447739)
demodulize 1.875757 0.005089 1.880846 ( 1.895737)
but split('::').last
becomes much slower if your class is nested deeper
Upvotes: 1
Reputation: 369438
Classes don't really have "names" in Ruby. A class is an object like any other object, it gets assigned to variables like any other object. A class doesn't have a name, just like a number or a string doesn't have a name.
Take this example:
foo = Class.new
Bar = foo
Baz = foo
Bar = nil
remove_const :Bar
What should the "name" of the class be in this example?
Well, there is a method called name
in the Module
class. What it does is the following: if the class object has been assigned to a constant for the first time, the name of that constant (note that even that is a fuzzy concept!) becomes the name of the class, otherwise the name will just be nil
.
Expanding on the example above:
foo = Class.new
foo.name
# => nil
Bar = foo
foo.name
# => 'Bar'
Bar.name
# => 'Bar'
Baz = foo
Baz.name
# => 'Bar'
Bar = nil
remove_const :Bar
foo.name
# => 'Bar'
Here's another example:
foo = Class.new
Bar = foo
Baz = foo
class Baz
class Quux; end
Xyzzy = Quux
end
foo::Xyzzy.name
# => 'Bar::Quux'
Note that even though Quux
is defined inside Baz
and accessed via foo::Xyzzy
it still prints Bar::Quux
as its name.
Also, two different classes can have the same name:
Foo = Class.new
Bar = Foo
Foo = nil
remove_const :Foo
Foo = Class.new
Baz = Foo
Foo = nil
remove_const :Foo
Bar.name
# => Foo
Baz.name
# => Foo
Bar == Baz
# => false
The "name" of a class is simply a debugging help for human readers, you should never use it for anything else, and never use it programmatically (or even depend on a specific structure of the string).
Upvotes: 2
Reputation: 9659
In vanilla Ruby, I'm pretty sure class.name.split('::').last
is the best way to go. But if you happen to be using ActiveSupport (if you're on Rails, this library will be loaded) there is an inflector called demodulize.
class Foo
class Bar
end
end
obj = Foo::Bar.new
puts obj.class.name.demodulize # => Bar
Upvotes: 4
Reputation: 11951
No, there isn't a method to return just the name of the class. Technically, the name is only accurate if it includes any outer modules and classes.
The #name
method is defined on the Module
class; see the documentation for more information.
Upvotes: 0