I get the result:
String.class # => Class
String.superclass # => Object
Class.class # => Class
Class.superclass # => Module
Both String and Class are objects of Class. Why is String's superclass Object while Class's superclass is Module?
You formulate question in a strange way. I have nothing to say besides "they are defined in this way".
class A
end
class B
end
class C < A
end
class D < B
end
p C.class # => Class
p C.superclass # => A
p D.class # => Class
p D.superclass # => B
Related
Here is an external class which has its class method overwritten.
class Foo
def class
"fooo"
end
end
class Boo < Foo
end
class Moo < Foo
end
Now I have an instance of the subclass. Is it possible to find out which class it belongs to?
foo.class # currently returns 'fooo', I want get Boo or Moo.
You could use instance_method to grab the class method from somewhere safe (such as Object) as an UnboundMethod, bind that unbound method to your instance, and then call it. For example:
class_method = Object.instance_method(:class)
# #<UnboundMethod: Object(Kernel)#class>
class_method.bind(Boo.new).call
# Boo
class_method.bind(Moo.new).call
# Moo
class_method.bind(Foo.new).call
# Foo
Of course, if you've also replaced Object#class (or Kernel#class) then all bets are off and you're in a whole new world of pain and confusion.
An object's class also happens to be the superclass of its singleton_class:
Boo.new.singleton_class.superclass
#=> Boo
Moo.new.singleton_class.superclass
#=> Moo
Foo.new.singleton_class.superclass
#=> Boo
I prefer #Stefan’s and #muistooshort's solutions, but here's an alternative.
class Foo
def class
"foo"
end
end
class Boo < Foo
end
class Who < Boo
def class
"who"
end
end
boo = Boo.new
boo.method(:class).super_method.call
#=> Boo
who = Who.new
who.method(:class).super_method.call
#=> "foo"
who.method(:class).super_method.super_method.call
#=> Who
More generally:
def my_class(obj)
m = obj.method(:class)
until m.owner == Kernel do
m = m.super_method
end
m.call
end
my_class(boo)
#=> Boo
my_class(who)
#=> Who
See Method#super_method.
This solution is a little hacky, but overriding class is pretty hacky in itself, so when in Rome, do as Romans do:
class Foo
def class
'fooo'
end
end
class Boo < Foo
end
boo = Boo.new
=> #<Boo:0x00007fd2361feba8>
boo.class
=> "fooo"
boo.inspect
=> "#<Boo:0x00007fd2361feba8>"
klass = boo.inspect.split(':').reject(&:empty?)[0..-2].join('::').sub('#<', '')
=> "Boo"
boo.is_a?(Kernel.const_get(klass))
=> true
This also works for classes in a module:
module Bar
class Foo
def class
'fooo'
end
end
class Boo < Foo
end
end
boo = Bar::Boo.new
=> #<Bar::Boo:0x00007fe5a20358b0>
boo.class
=> "fooo"
boo.inspect
=> "#<Bar::Boo:0x00007fe5a20358b0>"
klass = boo.inspect.split(':').reject(&:empty?)[0..-2].join('::').sub('#<', '')
=> "Bar::Boo"
boo.is_a?(Kernel.const_get(klass))
=> true
My understanding of instance_eval was that if I have module M then the following were equivalent:
module M
def foo
:foo
end
end
class C
class << self
include M
end
end
puts C.foo
equivalent to:
module M
def foo
:foo
end
end
class C
end
C.instance_eval do
include M
end
puts C.foo
However, the first example prints :foo and the second throws a NoMethodError? (Ruby 2.3.0)
In both cases above, if I had replaced:
include M
with:
def foo
:foo
end
ie directly defining the method rather than including a module then both cases would have resulted in a C.foo method being defined. Should I be surprised at this difference between include and defining the method directly?
Or does it ever even make sense to call include within the context of instance_eval? Should it only ever be called within a class_eval?
In each of these cases, what object are you calling include on? In your first example, you're calling include on C's singleton class:
class C
class << self
p self == C.singleton_class
include M
end
end
# => true
p C.foo
# => :foo
...so your include line is equivalent to C.singleton_class.include(M).
In your second example, however, you're calling include on C itself:
class C
end
C.instance_eval do
p self == C
include M
end
# => true
p C.foo
# => NoMethodError: undefined method `foo' for C:Class
p C.new.foo
# => :foo
...so you're doing the equivalent of C.include(M), which is the same as:
class C
p self == C
include M
end
# => true
p C.new.foo
# => :foo
What would work like you want would be to call instance_eval on C's singleton class:
class D
end
D.singleton_class.instance_eval do
p self == D.singleton_class
include M
end
# => true
p D.foo
# => :foo
Module#class_eval() is very different from Object#instance_eval(). The instance_eval() only changes self, while class_eval() changes both self and the current class.
Unlike in your example, you can alter class_instance vars using instance_eval though, because they are in the object scope as MyClass is a singleton instance of class Class.
class MyClass
#class_instance_var = 100
##class_var = 100
def self.disp
#class_instance_var
end
def self.class_var
##class_var
end
def some_inst_method
12
end
end
MyClass.instance_eval do
#class_instance_var = 500
def self.cls_method
##class_var = 200
'Class method added'
end
def inst_method
:inst
end
end
MyClass.disp
#=> 500
MyClass.cls_method
#=> 'Class method added'
MyClass.class_var
#=> 100
MyClass.new.inst_method
# undefined method `inst_method' for #<MyClass:0x0055d8e4baf320>
In simple language.
If you have a look in the upper class defn code as an interpreter, you notice that there are two scopes class scope and object scope. class vars and instance methods are accessible from object scope and does not fall under jurisdiction of instance_eval() so it skips such codes.
Why? because, as the name suggests, its supposed to alter the Class's instance(MyClass)'s properties not other object's properties like MyClass's any object's properties. Also, class variables don’t really belong to classes—they belong to class hierarchies.
If you want to open an object that is not a class, then you can
safely use instance_eval(). But, if you want to open a class definition and define methods with def or include some module, then class_eval() should be your pick.
By changing the current class, class_eval() effectively reopens the class, just like the class keyword does. And, this is what you are trying to achieve in this question.
MyClass.class_eval do
def inst_method
:inst
end
end
MyClass.new.inst_method
#=> :inst
How can I programmatically get the class on which the currently executing code is defined? I need to find the class when control flow runs through multiple method definitions due to super():
class A
def foo
puts(get_current_class)
end
end
class B < A
def foo
puts(get_current_class)
super
end
end
class C < B
def foo
puts(get_current_class)
super
end
end
C.new.foo
# => C
# => B
# => A
I know how to get the method name (using __callee__, caller_locations or __method__); but what about the class?
Since classes in ruby are also modules, this could be achieved with Module#nesting:
class A
def foo
puts(Module.nesting.first)
end
end
class B < A
def foo
puts(Module.nesting.first)
super
end
end
class C < B
def foo
puts(Module.nesting.first)
super
end
end
C.new.foo
# => C
# => B
# => A
Alternatively, if the goal is to construct a list of which methods may be called by the object's ancestor chain, then you could use Method#owner and Method#super_method (available since ruby version 2.2.0):
c = C.new
c.method(:foo).owner # => C
c.method(:foo).super_method.owner # => B
c.method(:foo).super_method.super_method.owner # => A
c.method(:foo).super_method.super_method.super_method # => nil
As a quick off-the-cuff implementation to programatically print all classes then, how about:
c = C.new
method = c.method(:foo)
while(method)
puts m.owner
method = method.super_method
end
# => C
# => B
# => A
(However, there is no guarantee that all of these methods will actually be invoked - as this is determined at runtime via super!)
I'm new to programming. Right now I'm studying Ruby. To my understanding, global variables are defined in the global namespace (so outside of any classes or functions). I'm reading something and it says global variables have a $ sign before them. What does that mean? Does it mean when I define a function or class and want to reference my global variable (let's say it is edmund = 123) I would have to reference it like this: $edmund?
so:
edmund = 123
def my_function()
456 + $edmund
end
Also are class variables (the ones that begin with ##) like instance variables (#) where you can access them by calling them through Class.classvariable? What is their purpose?
Global scope is scope that covers the entire program. Global scope is enjoyed by global variables, which are recognizable by their initial dollar-sign ($) character. They’re available everywhere and creating your own global variables can be tempting, especially for beginning programmers. But they’re not always a good idea.
$gvar = "I'm a global!"
class C
def examine_global
puts $gvar
end
end
c = C.new
c.examine_global # I'm a global!
Class variables begin with two at signs: ##var, for example. Despite their name, class variables aren’t class scoped. Rather, they’re class-hierarchy scoped. At its simplest, the idea behind a class variable is that it provides a storage mechanism that’s shared between a class and instances of that class, and that’s not visible to any other objects.
class Parent
##value = 100
end
class Child < Parent
##value = 200
end
class Parent
puts ##value
end
What gets printed is 200. The Child class is a subclass of Parent, and that means Parent and Child share the same class variables—not different class variables with the same names, but the same actual variables. When you assign to ##value in Child, you’re setting the one and only ##value variable that’s shared throughout the hierarchy—
that is, by Parent and Child and any other descendant classes of either of them.
And to give credit where its due - This explanation comes from "The Well Grounded Rubyist" by David A Black, one of the best resources to learn about Ruby.
Excellent question. Unfortunately, you just jumped down a rabbit hole, but it's one that you have to fall through eventually in ruby to start understanding the real intricacies.
For your first question, regarding the $-prefixed global variables. They are truly global:
def mk_foo() $foo ||= "foo"; end
$foo # => nil
mk_foo # => "foo"
$foo # => "foo"
mk_foo.object_id # => 70299647799620
$foo.object_id # => 70299647799620
As you can see, when $foo is defined within the mk_foo method, it is defined in the global space, and you can access it anywhere:
class CanSeeFoo
def see_foo() $foo; end
end
CanSeeFoo.new.can_see_foo
# => "foo"
CanSeeFoo.new.can_see_foo.object_id
# => 70299647799620
As for the class variable question, this is where the rabbit-hole begins. First, you are correct that ##-prefixed variables are referred to as "class variables" and #-prefixed variables are referred to as "instance variables".
Class variables are static across all subclasses (at all sub-levels of the inheritance tree) of the defining class. The implication here is that if any subclass changes the class variable, it will change in all related subclasses and up to the defining class.
class A; end
class B < A; ##foo = "foo"; end
B.class_variable_get(:##foo) # => "foo"
A.class_variable_get(:##foo)
# => raises NameError "uninitialized class variable ##foo in A"
class C < B; end
C.class_variable_get(:##foo) # => "foo"
class D < C
def self.change_foo(); ##foo = "bar"; end
def change_foo(); ##foo = "baz"; end
end
D.class_variable_get(:##foo) # => "foo"
class E < D; end
E.class_variable_get(:##foo) # => "foo"
D.change_foo # => "bar"
D.class_variable_get(:##foo) # => "bar"
E.class_variable_get(:##foo) # => "bar"
C.class_variable_get(:##foo) # => "bar"
B.class_variable_get(:##foo) # => "bar"
D.new.change_foo # => "baz"
D.class_variable_get(:##foo) # => "baz"
E.class_variable_get(:##foo) # => "baz"
C.class_variable_get(:##foo) # => "baz"
B.class_variable_get(:##foo) # => "baz"
A.class_variable_get(:##foo)
# => raises NameError "uninitialized class variable ##foo in A"
As for accessing class and instance variables, neither is accessible without the use of #instance_variable_get or ::class_variable_get until an accessor is defined. At present, ruby only has methods for defining accessors on instance variables, but it is simple enough to define the appropriate methods for the class variables:
class A
##foo = "foo"
# the second argument `true` adds the writer method `#bar=`
attr :bar, true
def self.foo(); ##foo; end
def self.foo=(v); ##foo = v; end
def initialize()
#bar = "bar"
end
end
class B < A; end
A.foo # => "foo"
B.foo = "foobar"
A.foo # => "foobar"
B.foo # => "foobar"
a = A.new
a.bar # => "bar"
a.bar = "baz"
a.bar # => "baz"
a.foo
# => raises NoMethodError: undefined method `foo' for #<A:0x ...
You can see the attribute accessor methods here in the ruby core docs: http://www.ruby-doc.org/core-1.9.3/Module.html#method-i-attr. Also, ActiveSupport (http://rubygems.org/gems/activesupport) has "cattr" methods for defining class variable accessors http://api.rubyonrails.org/v3.2.5/classes/Class.html#method-i-cattr_accessor.
That's the simple stuff. The next step is understanding the "singleton class" also known as the "eigenclass" or "metaclass" (Wikipedia: Metaclass) (remember, everything in ruby is an Object, including the Class and Module constructs). Here I will point you to an excellent post by Yehuda Katz: Metaprogramming in Ruby: It’s All About the Self, and another Stack Overflow question: class << self idiom in Ruby.
As a preview: The singleton class (not to be confused with the singleton design pattern) allows you to access methods and instance data for a specific class or module. For some related documentation, see the core docs: http://www.ruby-doc.org/core-1.9.3/Object.html#method-i-singleton_class
class A; end
class B < A;
class << self
def foo() #foo end
def foo=(v) #foo = v; end
end
end
B.foo = "foo"
class C < B; end
A.foo
# => raises NoMethodError: undefined method `foo' for A:Class
B.foo # => "foo"
C.foo # => nil
B.foo = "baz"
B.foo # => "baz"
C.foo # => nil
C.foo = "foo"
C.foo # => "foo"
B.foo # => "baz"
Lastly, remember to make use of the Ruby-Core docs. Most useful for understanding the above are:
http://www.ruby-doc.org/core-1.9.3/Object.html
http://www.ruby-doc.org/core-1.9.3/Module.html
http://www.ruby-doc.org/core-1.9.3/Class.html
The dollar sign is part of the variable name, so it has to be declared like this:
$edmund = 123
This is the same things for the instance and class variables: their names begin with # or ##.
Can someone help me make sense of the following? I have the following code in test.rb:
class Dog
end
// bark is declared outside of Dog class
def bark
puts 'Woof!'
end
then in irb:
>> source 'test.rb'
>> a = Dog.new
=> #<Dog:0x117f614>
>> a.bark
Woof!
=> nil
Why does method bark exist in Dog instance even though it is declared outside of the class? Because it's in the same file? Thanks!
When you create a method in the "global" scope (outside of any class), that method is made a private method of Object:
#!/usr/bin/ruby1.8
class Dog
end
p Object.respond_to?(:bark, true) # => false
def bark
puts "Woof!"
end
p Object.respond_to?(:bark, true) # => true
Object is in the ancestry chain of all objects, including Dog:
dog = Dog.new
p dog.class.name # => "Dog"
p dog.class.superclass.name # => "Object"
Therefore dogs (and indeed all objects) now know how to bark. However, the method being private, you'll have to use instance_eval to call it with an explicit receiver:
dog.instance_eval { bark } # => "Woof!"
Or you can call it with an implicit receiver with no gymnastics needed:
bar # => "Woof!"
Your exact example doesn't work in Ruby 1.9. (Apart from the bad comment syntax.)
However, declaring a method in the top level scope will make it a private method on Object, apparently:
>> Object.private_methods.include? :bark
=> true
Perhaps in your Ruby (1.8?), this is a public method?