I want an inherited ruby class to 'know' its class name via a class method. This is best illustrated by a contrived example:
class Parent
def self.whoami
??
end
end
class Child < Parent
#No code should be needed.
end
So I should be able to call:
Parent.whomai
and expect a return of "Parent" I should then be able to call:
Child.whoami
and expect a return of "Child" I have a feeling that in conventional languages this might not be possible. But Ruby's metaprogramming model has amazed me before. Any thoughts? Thanks in advance.
A Class Method is a method where the CLASS is the receiver, so to find the object upon which the method is invoked (what you appear to be trying to do here) simply inspect the value of self.
class Parent
def self.whoami
self
end
end
class Child < Parent
end
puts Parent.whoami #=> Parent
puts Child.whoami #=> Child
The method to get the name of a class (module, actually) is just Module#name. There's no need to write your own:
Parent.name # => 'Parent'
Child.name # => 'Child'
However, in Ruby, there really is no such thing as a "class name" as there is in some other languages. In Ruby, a class is simply an object like any other object which gets assigned to a variable like any other variable.
All the Module#name method does is loop through all the constants in the system and check whether the module has been assigned to any one of them, and return that constant's name or nil if it cannot find any.
So, just like any other object, the "name" of a class is really nothing but whatever variable you use to refer to it.
Example:
foo = Class.new
foo.name # => nil
Now, the "name" of the class is foo. However, Module#name returns nil, because foo is not a constant.
bar = foo
bar.name # => nil
Now, the "name" of the class is both foo and bar, but Module#name obviously still returns nil.
BAZ = foo
foo.name # => 'BAZ'
Now, since the class has been assigned to a constant, that constant's name will be considered that class's name …
BAZ = nil
foo.name # => 'BAZ'
… even after the constant has been assigned to something different and …
QUX = foo
QUX.name # => 'BAZ'
… even after the class has been assigned to a different constant.
Module#to_s uses Module#name if it is not nil, so, to print the name of a class, you simply do
puts Parent
There's really absolutely no need for all the complex fluff in the other answers.
Isn't that what Parent.class will tell you?
class Parent
def self.whoami
self.to_s
end
end
class Child < Parent
end
> Parent.whoami
=> "Parent"
> Child.whoami
=> "Child"
Suppose you class:
class ABC
def self.some_method
self.name #it will return 'ABC'
self.name.constantize #it will return ABC
end
end
Related
When using class inheritance, is there a way to order the methods? I want them ordered, because I am inheriting from a class that executes all public methods, in order.
For example:
class Foo
def action_two
puts "action 2"
end
end
class Bar < Foo
def action_one
puts "action 1"
end
end
Bar.instance_methods # => [:action_two, :action_one, ...]
...and I would like it to return [:action_one, :action_two, ...]
The documentation doesn't say anything about the order and I actually get them in the order you want when I use Ruby 2.1.2. If you want them to come out in a specific order then I think you'll have to do it yourself. You could use the include_super parameter to instance_methods to get just the current class's methods and then ask superclass for its methods:
class Bar < Foo
#...
def self.instance_methods
super(false) + superclass.instance_methods
end
end
If you're going to be dealing with BasicObject as a possible superclass then you'll want to add a superclass.nil? check before calling superclass.instance_methods.
If you're inheritance hierarchy is deep then you should be able to put this hackery into the lowest base class (Foo in this case) and let the subclasses pick it up through inheritance.
In order to do that, you have to define Bar#action_one before inheriting Foo into Bar. Since class inheritance is determined at the creation time of the class that inherits, you cannot do that as is.
A way to overcome this is to make Foo a module instead of a class, and include it into Bar after Bar#action_one is defined.
module Foo
def action_two
puts "action 2"
end
end
class Bar
def action_one
puts "action 1"
end
include Foo
end
Bar.instance_methods
# => [:action_one, :action_two, ...]
Bar.ancestors.each_with_object([]) { |a, o| o << a.instance_methods }.flatten.uniq
Since we know that class is also an object of class Class. I have a doubt here.
I have a class defined here Foo and a method which prints the object.
class Foo
def bar
puts self
end
puts self
end
When I do Foo.new.bar o/p will be # <Foo:0x935c740>
which represents an object of class Foo.
Why not the self outside the method prints #<Class: 0x..> as its an object of class Class?
Sorry if my question is wrong but please clarify it.
Here is a little different way to define a classes/objects:
klass = Class.new {
puts self
def bar
puts self
end
}
# #<Class:0x3fbdbb8>
As you can see, it outputs #<Class:0x3fbdbb8>. So its class is Class. You can check it via class method:
klass.class
# => Class
When you name your class with uppercase letter (for example Example) for the first time, it use it as output instead of cryptic name like: #<Class:0x3fbdbb8>.
Foo = Class.new {
puts self
def bar
puts self
end
}
Still outputs cryptic name because Foo ='s part hasn't been evaluated yet.
puts Foo
Outputs correct name - Foo
What if I name it again?
Qux = Foo
# => Foo
Nothing. Foo will be Foo forever.
Names of classes and modules are constant in ruby. So when you are defining a class you are creating an object of class Class and providing it with a constant name and hence when you do a puts self in a class context, it gives a class name instead of something like #<Class: 0x..>
class Invoice
def Invoice.generate(order_id, charge_amount, credited_amount = 0.0)
Invoice.new(:order_id => order_id, :amount => charge_amount, :invoice_type => PURCHASE, :credited_amount => credited_amount)
end
end
Why would you create Invoice.generate inside Invoice class rather than self.generate?
self.generate is easier to work with, whereas Invoice.generate is arguably more explicit. Other than that, there's no difference between the two.
Explanation
You can define a method on any instance using this form
def receiver.method(args)
end
Check this out
class Foo
end
def Foo.bar
"bar"
end
Foo.bar # => "bar"
And yes, I mean any instance. It's absolutely possible that one instance has some method while another doesn't
f = Foo.new
def f.quux
'quux'
end
f2 = Foo.new
f.quux # => "quux"
f2.quux # => # ~> -:20:in `<main>': undefined method `quux' for #<Foo:0x007fe4e904a6c0> (NoMethodError)
A reminder: inside of class definition (but outside of method definitions) self points to that class.
class Foo
# self is Foo
end
So, armed with this knowledge, the difference between self.generate and Invoice.generate should be obvious.
Under normal circumstances, it would practically have no difference from def self.generate.
The only edge case I can think of is if you have a nested class with the same name, then the explicit version would apply only to the nested class.
class A
def self.x
name
end
def A.y
name
end
class A
# nested class A::A
end
def self.p
name
end
def A.q
name
end
end
> A.x # => "A"
> A.y # => "A"
> A.p # => "A"
> A.q # => NoMethodError: undefined method `q' for A:Class
> A::A.q # => "A::A"
As you see, after a nested class with the same name is defined, subsequent explicit class method definitions made with the class name refer to the nested class, but explicit definitions made beforehand refer to the original.
Implicit definitions made with self always refer to the base class.
You have 2 ways for defining a class method.
1) You can use the name of the class directly
class Test #Test is now an instance of a built-in class named Class
def Test.class_method
"I'm a class method."
end
end
2) You can use the self variable, which is always pointing to the current object
class Test
def self.class_method
"I'm a class method."
end
end
Once you understand that classes are objects, this use of the self variable to define a class method finally makes sense.
The value of self
Not too surprinsingly, when you are inside a class method, the value of self refers to the object that holds the class structure (the instance of class Class). This means that :
class Test
def self.class_method
self.x
end
end
is equivalent to :
class Test
def self.class_method
Test.x
end
end
When you are inside an instance method, the value of self still refers to the current object. This time however, the current object is an instance of class Test, not an instance of class Class.
More info. : http://www.jimmycuadra.com/posts/self-in-ruby
class A
def set(v)
##v = v
end
def put
puts ##v
end
end
class B < A
end
class C < A
end
B.new.set 'b'
B.new.put # => b
C.new.set 'c'
C.new.put # => c
B.new.put # => c
Why? And how should I write this to have 'b' in last B.new.put?
Here is a nice article on the subject - Class and Instance Variables In Ruby.
Basically, what you can do is:
class A
class << self
attr_accessor :class_var
end
def set_class_var(value)
self.class.class_var = value
end
def get_class_var
self.class.class_var
end
end
class B < A; end
A.class_var = 'a'
B.class_var = 'b'
puts A.class_var # => a
puts B.class_var # => b
A.new.set_class_var 'aa'
B.new.set_class_var 'bb'
puts A.new.get_class_var # => aa
puts B.new.get_class_var # => bb
To understand it you should think about A as an instance of Class class (and that's how it is in Ruby). But every object in Ruby has its own singleton class that stores object-specific stuff like methods defined on object itself:
a = A.new
def a.foo
puts 'foo'
end
In that case foo is method defined only for a object and not for every instance of A class. And another way to define method in object's singleton class is like that:
class << a # open a's singleton class
def bar # define method that will be available only on 'a' object
puts 'bar'
end
end
In the first code snippet we use that approach to define class_var attribute accessor in the context of singleton class of our A class (it's a bit tricky, so you need to think about it). As the result class itself has class_var variable as well as its descendant class B. The difference is that every one of them has its own class_var variable that do not interfere.
Another option is to pull out class_inheritable_accessor code from Rails and include its behavior in your classes. See here for a good discussion and the guts of the code.
Perhaps you don't really want a class variable, though.
Assigning a value to a class variable (an ## variable) sets it for EVERY instance of the class. It even "sets" it for instances that "aren't created yet." So, consider this...
B.new.set 'b' # OK, that set ##v for that particular instance of B
B.new.put # Hey, you just created *another* new instance of B!
How can ##v have a value in that one? The second object's value of ##v would be unset, except for the fact that ##v is a class variable, so it has the same value for every instance of the class.
At the top level, method definition should result in private methods on Object, and tests seem to bear this out:
def hello; "hello world"; end
Object.private_instance_methods.include?(:hello) #=> true
Object.new.send(:hello) #=> "hello world"
However, the following also works at top level (self.meta is the eigenclass of main):
self.meta.private_instance_methods(false).include?(:hello) #=> true
It appears that the hello method is simultaneously defined on the eigenclass of main as well as on Object. What's going on? Note that the false parameter to private_instance_methods excludes super class methods from the method list.
First of all, this behavior and the underlying reasoning have always existed; it's nothing new to 1.9. The technical reason it happens is because main is special and treated differently than any other object. There's no fancy explanation available: it behaves that way because it was designed that way.
Okay, but why? What's the reasoning for main to be magical? Because Ruby's designer Yukihiro Matsumoto thinks it makes the language better to have this behavior:
Is so, why are top-level methods not made singleton-methods on this object,
instead of being pulled in as instance methods on the Object class
itself
(and hence into all other classes i.e. more namespace pollution than is
usually intended). This would still allow top-level methods to call other
top-level methods. And if the top-level object were referred to by
some
constant like Main, then those methods could be called from anywhere
with
Main.method(...).
Do you really wish to type
"Main.print" everywhere?
Further on in the discussion, he explains that it behaves this way because he feels the "assumption is natural."
EDIT:
In response to your comment, your question is aimed at why main's eigenclass seems to report hello as a private instance method. The catch is that none of the top-level functions are actually added to main, but directly to Object. When working with eigenclasses, the instance_methods family of functions always behave as if the eigenclass is still the original class. That is, methods defined in the class are treated as being defined directly in the eigenclass. For example:
class Object
private
def foo
"foo"
end
end
self.send :foo # => "foo"
Object.private_instance_methods(false).include? :foo # => true
self.meta.private_instance_methods(false).include? :foo # => true
class Bar
private
def bar
"bar"
end
end
bar = Bar.new
bar.send :bar # => "bar"
Bar.private_instance_methods(false).include? :bar # => true
bar.meta.private_instance_methods(false).include? :bar # => true
We can add a method directly to main's eigenclass, though. Compare your original example with this:
def self.hello; "hello world"; end
Object.instance_methods.include? :hello # => false
self.meta.instance_methods.include? :hello # => true
Okay, but what if we really want to know that a given function is defined on the eigenclass, not the original class?
def foo; "foo"; end #Remember, this defines it in Object, not on main
def self.bar; "bar"; end #This is defined on main, not Object
foo # => "foo"
bar # => "bar"
self.singleton_methods.include? :foo # => false
self.singleton_methods.include? :bar # => true