I've just made this experiment:
class A < Hash
def foo
'foo'
end
end
class A < Hash
def bar
'bar'
end
end
So far I get the result I expected, the second declaration extends the first one. However I was surprised of this:
class A
def call
puts foo
puts bar
end
end
The code above works, but only if I declare it later. Otherwise I get:
TypeError: superclass mismatch for class A
Can I assume that in Ruby, it is safe skipping the superclass specification without side effects after making sure that the "original-first" declaration was parsed?
You are able to declare inheritance only on the first occurince of the class definition, so below variants will work:
When you've defined the same class inheritance:
class A < Hash
end
class A < Hash
end
When you've used default inheritance in the second case, that is treated as undefined inheritance:
class A < Hash
end
class A
end
When you've used default inheritance in both cases, the default inheritance is of Object class:
class A
end
class A
end
And below will not:
When you've used default inheritance in the first case, and next you tried to redefine it explicitly:
class A
end
class A < Hash
end
TypeError: superclass mismatch for class A
When you've used specified inheritance (in example String) in the first case, and next you tried to redefine it explicitly (in example with Hash):
class A < String
end
class A < Hash
end
TypeError: superclass mismatch for class A
#Малъ Скрылевъ explained this case a better way, so I wouldn't attempt that. But I would show you another way to do this.
One way to avoid the error is in your situation :
Instead of writing
class A
def call
puts foo
puts bar
end
end
Write it as below using Module#class_eval:
Evaluates the string or block in the context of mod, except that when a block is given, constant/class variable lookup is not affected. This can be used to add methods to a class. module_eval returns the result of evaluating its argument.
A.class_eval do
def _call
puts foo
puts bar
end
end
Related
How can one get the class a method was defined in?
I've found how to look up descendents and ansestors: Look up all descendants of a class in Ruby
But that doesn't necessarily get me the defining class (last defining class really).
I've found how to get the calling class:
Ruby Inheritance Get Caller Class Name
But I want the opposite. I would like how to get the defining class.
I've also tried Module.nesting. That gets me what I want in this case, but I worry it will be inconsistent and not acceptable in a larger codebase of which I don't have ultimate control.
puts RUBY_VERSION
# Test class vs super.
class Super
def test_func
puts "#{self.class}, #{ __method__}"
end
end
class Child < Super
def test_func2
self.test_func
end
end
Child.new.test_func
I had hoped for:
1.8.7
Super, test_func
But got:
1.8.7
Child, test_func
You asked self.class of Child object and you got it.
You need use Method#owner to return the class or module that defines the method.
class Super
def test_func
puts "#{method(__method__).owner}, #{ __method__}"
end
end
class Child < Super
def test_func2
self.test_func
end
end
Child.new.test_func
# will print: Super, test_func
or just
Child.new.method(:test_func).owner
#=> Super
While creating a class, we use the keyword class like:
class Abc
Z = 5
def add
puts "anything here"
end
end
In console, Abc.class # => Class
How does Abc internally become a class? What is the difference between class and Class?
It would be great if anyone could explain how class constants and method are internally called, and if a method is not defined, then how we get the exception "undefined class method". What is the internal logic behind it?
There are three different things here:
class is a keyword, which is used to define or reopen a class
Object#class is a method, which returns the class of a given object
Class is the class which all classes are an instance of (including Class itself)
ndn's answer gives a nice overview of the different things "class" could refer to.
To answer your specific question:
How does Abc internally become a class?
Almost like any other object.
class Abc
end
is equivalent to:
Abc = Class.new do
end
It creates a new instance of Class and assigns it to the constant Abc.
To see what the different "class" things in Ruby mean, check out my other answer.
As for how methods are looked up:
There are multiple places a method can come from:
The class of the object
The parent of the class of the object
Modules, which are included/prepended
The singleton class of the object
The order of lookup is the following:
If it exists, the singleton class
Prepended modules
Methods defined in the class
Included modules
Recursively, the above rules for the parent class
There are a few things that have to be noted here:
If multiple modules are included/prepended, they will be looked up in the reverse order of how they were included/prepended
If a module was already included/prepended in one of the parrents, it won't be included/prepended again
If using these rules the method was not found til the very start of the hierarchy (BasicObject), the ancestor chain is searched again for a different method, called method_missing
BasicObject#method_missing is defined so that it throws a NoMethodError and that is where the error comes from
module M1
def foo
puts 'Defined in M1'
end
end
module M2
def foo
puts 'Defined in M2'
end
end
class C
include M1
prepend M2
def foo
puts 'Defined in C'
end
def method_missing(method_name)
puts 'Method missing' if method_name == :foo
end
end
c = C.new
# singleton method
def c.foo
puts "Defined in c's singleton"
end
puts c.singleton_class.ancestors
# => [#<Class:#<C:0xa2d0f8>>, M2, C, M1, Object, Kernel, BasicObject]
# ^ the singleton class,
# the prepended module,
# the C class itself,
# the included module,
# the rest of the hierarchy
# (Object is the implicit parent of all classes with no explicit parent)
with class Abc you define a class.
Abc.class is returning the Type, and the type of Abc is a Class
another example:
1337.class
=> Fixnum
"hi babe!".class
=> String
12.55.class
=> Float
(1..12).class
=> Range
so as you can see, each "datatype" is a class. in your case Abc is also a Datatype. And for the end of that chain, the class of a class is Class! :-)
Answering second par of the question, undefined class method happens when method you called is not present in such class - classes are just objects in Ruby, and as such they have their own set of methods. Ruby has several ways to define class methods, most common is probably
class Klass
def self.klass_method
...
end
end
the other is
class Klass
# some ordinary instance methods here
class << self
def klass_method
# this is class method
end
end
end
Some Rubyists prefer the latter, as it keeps all class methods in single block, but they are equivalent.
In Ruby, I have a DAO class, which is extended by a class that makes managing the connections easier, which is extended by a class that represents and manipulates data in a DB, which is further extended by another class. To use an animal metaphor it would look like this:
class Animal
...
end
class Mammal < Animal
...
end
class Feline < Mammal
...
end
class Cat < Feline
...
end
class Lion < Cat
...
end
...
In PHP, there is __destruct method that runs when you destroy/delete a class. And should that class extend another class, you simply add parent::__destruct() to the class's __destruct method like this:
public function __destruct() {
// Clean up code for this class here
...
// Execute clean up code for Parent class
parent::__destruct();
}
I could have a similar method for all the classes except Animal. Since it doesn't extend anything, the parent::__destruct(); line is no longer valid.
However, as I understand it, Ruby doesn't have a method like this for its objects. A finalizer can be set, but I decided to just put in a cleanup method I can call whenever I want to destroy/delete a class. That would take care of anything that needed doing prior to my setting the class to nil.
This raises a new problem though. If the method is always named cleanup and I call lion_instance.cleanup, I assume it calls the Lion#cleanup. How then to get it to call the cleanup in class Cat and then Feline and on down the chain?
Or is this a wrong approach and you have a better idea?
The Ruby idiom for this is to yield to a block which does work, and when the block returns, do cleanup. Ruby's built-in "File.open" does this:
File.open("/tmp/foo") do |file|
file.puts "foo"
end
When the block ends, the file is closed for you, without you having to do anything. This is an excellent idiom. Here's how you might implement something like that:
class Foo
def self.open(*args)
foo = new(*args)
yield foo
foo.close
end
def initialize
# do setup here
end
def close
# do teardown here
end
end
And to use it:
Foo.open do |foo|
# use foo
end
Foo#close will be caused automatically after the end
This will work with subclassing as well. That's because class methods are inherited just as are instance methods. Here's the superclass:
class Superclass
def self.open(*args)
o = new(*args)
yield o
o.close
end
def initialize
# common setup behavior
end
def close
# common cleanup behavior
end
end
and two derived classes:
class Foo < Superclass
def initialize
super
# do subclass specific setup here
end
def close
super
# do subclass specific teardown here
end
end
class Bar < Superclass
def initialize
super
# do subclass specific setup here
end
def close
super
# do subclass specific teardown here
end
end
to use:
Foo.open do |foo|
# use foo
end
Bar.open do |bar|
# use bar
end
If you really need to make sure that cleanup happens no matter what, then use an ensure clause in the class method:
def self.open(*args)
foo = new(*args)
begin
yield foo
ensure
foo.close
end
end
This way, cleanup happens even if there is an exception in the block.
You can use ObjectSpace.define_finalizer
Something like:
class Animal
def initialize
ObjectSpace.define_finalizer(self, proc { # your code })
end
end
Well since no one answered your question about the method moving its way up the inheritance chain...
class Cat
def rawr
puts "rawr"
end
end
class Kitty < Cat
def rawr
puts "meow"
super
end
end
Cat.new.rawr
"Rawr"
Kitty.new.rawr
"rawr"
"meow"
Within a method, you can access the superclass's method of the same name by calling super.
class << Awesomeness
What is this << for? I searched, but the results only tell me about string concatenation...
While it's true that class << something is the syntax for a singleton class, as someone else said, it's most often used to define class methods within a class definition. But these two usages are consistent. Here's how.
Ruby lets you add methods to any particular instance by doing this:
class << someinstance
def foo
"Hello."
end
end
This adds a method foo to someinstance, not to its class but to that one particular instance. (Actually, foo is added to the instance's "singleton class," but that's more or less an implementation quirk.) After the above code executes, you can send method foo to someinstance:
someinstance.foo => "Hello."
but you can't send foo to other instances of the same class. That's what << is nominally for. But people more commonly use this feature for syntactic gymnastics like this:
class Thing
def do_something
end
class << self
def foo
puts "I am #{self}"
end
end
end
When this code -- this class definition -- executes, what is self? It's the class Thing. Which means class << self is the same as saying "add the following methods to class Thing." That is, foo is a class method. After the above completes, you can do this:
t = Thing.new
t.do_something => does something
t.class.foo => "I am Thing"
t.foo => NoMethodError: undefined method `foo'
And when you think about what << is doing, it all makes sense. It's a way to append to a particular instance, and in the common case, the instance being appended to is a class, so the methods within the block become class methods.
In short, it's a terse way to create class methods within a class definition block. Another way would be to do this:
class Thing
def self.foo
# ...
end
end
Same thing. Your example is actually a syntax error, but if you understand how << is used with instances and the class keyword, you'll know how to correct it.
<< is the syntax for "Singleton class definition". Here is an example of where/how it is "typically" used.
In a = "abc"; a << "xyz" it is the syntax for "appending data" (to string, array etc.)
If you want inheritance (based on your question title), you want a single <:
class Awesome < ParentAwesomeness
The code you provide isn't valid ruby:
class Awesomeness
end
class Awesome << Awesomeness
end
SyntaxError: (irb):3: syntax error, unexpected tLSHFT, expecting '<' or ';' or '\n'
i've got a module that wants to use data provided by the class that included it - but at the class level, not the instance level.
the goal is to have class 'metadata' provided to a module that the class includes, so that the module can use the metadata during the included call.
this works:
module Bar
def value
#value
end
def baz
puts "the value is: #{value}"
end
end
module Foo
def self.included(mod)
mod.extend(Bar)
mod.baz
end
end
class MyClass
#value = "my class defined this"
include Foo
end
the output of this code is
the value is: my class defined this
i'm not sure if the use of #value is good or not... it seems odd to me that i require this to be set before the include Foo happens, not from a technical perspective (i know why it's required to be done in this order) but from an idiomatic or usability perspective.
... is there a better way / more idiomatic way of accomplishing this?
If you really want to use the class metadata in the moment you're including a module, given the 'included' method runs on its own scope, it's best to have a class method providing the metadata to it.
Also, if the metadata is not going to be manipulated, its better to declare it as a constant.
module Bar
def self.included(base)
puts "the value is: #{base.metadata}"
end
end
class MyClass
VALUE = "MyClass metadata"
def self.metadata
VALUE
end
include Bar
end
class OtherClass
VALUE = "OtherClass metadata"
def self.metadata
VALUE
end
include Bar
end
Of course you can declare the metadata anyway you want, as long as its accessible by a class method to your Module.
Also, its not common to do these kind of metadata manipulation in the module's 'included' method and the necessity of ordering your statements on the class level is a bit brittle, so you might want to try to find a different solution to your original problem instead.
If you want to the class to pass an argument to the mixin, then why not use one of the Ruby constructs that actually does allow passing an argument?
class Object
private
def Bar(metadata)
Module.new do
include Bar
define_singleton_method(:included) do |base|
puts "the value is: #{metadata}"
end
end
end
end
module Bar
# put common behavior here
end
class MyClass
include Bar 'MyClass metadata'
end
class OtherClass
include Bar 'OtherClass metadata'
end
This is a pretty common idiom that is for example used by the delegate library in the stdlib.