How to properly destroy a class - ruby

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.

Related

Accessing the name of an anonymous class in superclass' self.inherited

I would like to access a class' name in its superclass MySuperclass' self.inherited method. It works fine for concrete classes as defined by class Foo < MySuperclass; end but it fails when using anonymous classes. I tend to avoid creating (class-)constants in tests; I would like it to work with anonymous classes.
Given the following code:
class MySuperclass
def self.inherited(subclass)
super
# work with subclass' name
end
end
klass = Class.new(MySuperclass) do
def self.name
'FooBar'
end
end
klass#name will still be nil when MySuperclass.inherited is called as that will be before Class.new yields to its block and defines its methods.
I understand a class gets its name when it's assigned to a constant, but is there a way to set Class#name "early" without creating a constant?
I prepared a more verbose code example with failing tests to illustrate what's expected.
Probably #yield has taken place after the ::inherited is called, I saw the similar behaviour with class definition. However, you can avoid it by using ::klass singleton method instead of ::inherited callback.
def self.klass
#klass ||= (self.name || self.to_s).gsub(/Builder\z/, '')
end
I am trying to understand the benefit of being able to refer to an anonymous class by a name you have assigned to it after it has been created. I thought I might be able to move the conversation along by providing some code that you could look at and then tell us what you'd like to do differently:
class MySuperclass
def self.inherited(subclass)
# Create a class method for the subclass
subclass.instance_eval do
def sub_class() puts "sub_class here" end
end
# Create an instance method for the subclass
subclass.class_eval do
def sub_instance() puts "sub_instance here" end
end
end
end
klass = Class.new(MySuperclass) do
def self.name=(name)
#name = Object.const_set(name, self)
end
def self.name
#name
end
end
klass.sub_class #=> "sub_class here"
klass.new.sub_instance #=> "sub_instance here"
klass.name = 'Fido' #=> "Fido"
kn = klass.name #=> Fido
kn.sub_class #=> "sub_class here"
kn.new.sub_instance #=> "sub_instance here"
klass.name = 'Woof' #=> "Woof"
kn = klass.name #=> Fido (cannot change)
There is no way in pure Ruby to set a class name without assigning it to a constant.
If you're using MRI and want to write yourself a very small C extension, it would look something like this:
VALUE
force_class_name (VALUE klass, VALUE symbol_name)
{
rb_name_class(klass, SYM2ID(symbol_name));
return klass;
}
void
Init_my_extension ()
{
rb_define_method(rb_cClass, "force_class_name", force_class_name, 1);
}
This is a very heavy approach to the problem. Even if it works it won't be guaranteed to work across various versions of ruby, since it relies on the non-API C function rb_name_class. I'm also not sure what the behavior will be once Ruby gets around to running its own class-naming hooks afterward.
The code snippet for your use case would look like this:
require 'my_extension'
class MySuperclass
def self.inherited(subclass)
super
subclass.force_class_name(:FooBar)
# work with subclass' name
end
end

Best way to add methods to a Class in execution time

I have to add methods to Class in execution time.
class ExtendableClass
end
The methods to add are declared in independent Classes.
module ExtensionClassOne
def method_one
end
end
module ExtensionClassTwo
def method_two
end
end
I'm looking for an (elegant) mechanism to add all the extension class methods into the ExtendableClass.
Approach 1
I'm thinking in explicily include the extension classes like:
ExtendableClass.send( :include, ExtensionClassOne )
ExtendableClass.send( :include, ExtensionClassTwo )
but it looks a little forced to have to call this private method every time I define a new extension class.
Approach 2
So I was looking for an automatic way to include this methods into my ExtendableClass class.
I'm thinking in declare an specific ancestor for this extension classes:
class ExtensionClassOne < Extension
def method_one
end
end
and then I'd need a mechanism to know all the childs of a class... something like the oposite of ancestors.
Once I have this list I can easily ExtendableClass.include all the list of classes. Even if I have to call to the private method here.
Approach 3
Also inheriting from the Extension class and detect in declaration time when this class is used as ancestor. In the way that the ActiveSupport.included method works, like an event binding. Then make the include there.
Any solution for implement approach 2 or approach 3? Do you recommend approach 1? New approachs?
#fguillen, you are right that the "explicit way is the cleanest approach". Since that is so, why don't you use the most "explicit" code which could be imagined:
class Extendable
end
class Extendable
def method_one
puts "method one"
end
end
class Extendable
def method_two
puts "method two"
end
end
...In other words, if you are defining a module which will be automatically included in a class as soon as it is defined, why bother with the module at all? Just add your "extension" methods directly to the class!
Approach 4 would be to define a macro on class level in Object
class Object
def self.enable_extension
include InstanceExtension
extend ClassExtension
end
end
and calling this macro in all your classes you want to be extended.
class Bacon
enable_extension
end
Car.enable_extension
This way,
you don't have to use #send to circumvent encapsulation (Approach 1)
you can inherit from any Class you want, because everything inherits from Object anyway (except 1.9's BasicObject)
the usage of your extension is declarative and not hidden in some hook
Downside: you monkeypatch build-in Classes and may break the world. Choose long and decriptive names.
Edit: Given your answer to my comment on the question I suppose this is not what you wanted. I see no problem with your "Approach 1" in this case; it's what I'd do. Alternatively, instead of using send to bypass the private method, just re-open the class:
class ExtendableClass
include ExtensionOne
end
Assuming I understand what you want, I'd do this:
module DelayedExtension
def later_include( *modules )
(#later_include||=[]).concat( modules )
end
def later_extend( *modules )
(#later_extend||=[]).concat( modules )
end
def realize_extensions # better name needed
include *#later_include unless !#later_include || #later_include.empty?
extend *#later_extend unless !#later_extend || #later_extend.empty?
end
end
module ExtensionOne
end
module ExtensionTwo
def self.included(klass)
klass.extend ClassMethods
end
module ClassMethods
def class_can_do_it!; end
end
end
class ExtendableClass
extend DelayedExtension
later_include ExtensionOne, ExtensionTwo
end
original_methods = ExtendableClass.methods
p ExtendableClass.ancestors
#=> [ExtendableClass, Object, Kernel, BasicObject]
ExtendableClass.realize_extensions
p ExtendableClass.ancestors
#=> [ExtendableClass, ExtensionOne, ExtensionTwo, Object, Kernel, BasicObject]
p ExtendableClass.methods - original_methods
#=> [:class_can_do_it!]
The included method is actually a hook. It is called whenever you are inherited from:
module Extensions
def someFunctionality()
puts "Doing work..."
end
end
class Foo
def self.inherited(klass)
klass.send(:include, Extensions) #Replace self with a different module if you want
end
end
class Bar < Foo
end
Bar.new.someFunctionality #=> "Doing work..."
There is also the included hook, which is called when you are included:
module Baz
def self.included(klass)
puts "Baz was included into #{klass}"
end
end
class Bork
include Baz
end
Output:
Baz was included into Bork
A very tricky solution, I think too much over-engineering, would be to take the inherited hook that #Linux_iOS.rb.cpp.c.lisp.m.sh has commented and keep all and every child class in a Set and combined it with the #Mikey Hogarth proposition of method_missing to look for all this child class methods every time I call a method in the Extendable class. Something like this:
# code simplified and no tested
# extendable.rb
class Extendable
##delegators = []
def self.inherited( klass )
##delegators << klass
end
def self.method_missing
# ... searching in all ##delegators methods
end
end
# extensions/extension_one.rb
class ExtensionOne < Extendable
def method_one
end
end
But the logic of the method_missing (and respond_to?) is gonna be very complicate and dirty.
I don't like this solution, just let it here to study it like a possibility.
After a very interesting propositions you have done I have realized that the explicit way is the cleanest approach. If we add a few recommendations taking from your answers I think I'm gonna go for this:
# extendable.rb
class Extendable
def self.plug( _module )
include( _module )
end
end
# extensions/extension_one.rb
module ExtensionOne
def method_one
puts "method one"
end
end
Extendable.plug( ExtensionOne )
# extensions/extension_two.rb
module ExtensionTwo
def method_two
puts "method two"
end
end
Extendable.plug( ExtensionTwo )
# result
Extendable.new.method_one # => "method one"
Extendable.new.method_two # => "method two"

Ruby : Invoke overridden method of parent class, in child class

Say I have class B derived from class A
Is it possible to invoke overrided method of A like this?
class A
def method1
end
def method2
end
end
class B < A
def method1
### invoke method2 of class A is what I want to do here
end
def method2
end
end
# not exactly duplicate to How do I call an overridden parent class method from a child class? , but we seem want to do the same thing.
I'm assuming here that B is supposed to inherit from A and you simply made a typo in your example code. If this is not the case, there is no way to do what you want.
Otherwise you can do what you want using reflection by binding A's method2 instance method to your current B object and calling it like this:
class A
def method1
end
def method2
end
end
class B < A
def method1
A.instance_method(:method2).bind(self).call
end
def method2
end
end
Note though that you shouldn't pull out the big black-magic-guns like this unless you really need to. In most cases redesigning your class hierarchy so that you don't need to do this is the better alternative.
You can create a synonym for parent method using alias statement and call it from the overriden method:
class A
def method1
puts '1'
end
def method2
puts '2'
end
end
class B < A
alias parent_method1 method1
alias parent_method2 method2
def method1
parent_method2
end
def method2
end
end
b = B.new
b.method1 # => 2
The answer of #sepp2k is technically correct, however I would like to explain why this technique is not appropriate in my opinion (so the question is technically interesting, but leads to the wrong goal):
Ruby does not allow to call super.method2 in the context of method1called in an instance of B, because it is just wrong to do it. Class inheritance should be used when your instances are specializations of the superclass. That includes that you normally only expand behavior, by calling super and doing something additionally before or after that call.
There are languages like Java and others, that allow to call super for another method, and that leads to something similar to spaghetti code, but the object-oriented way. No one understands when which methods are called, so try to avoid it.
So try to find the reason why you want to change the call, and fix that. If your method1 in A is wrong implemented in B, then you should not subclass is.

How do I call a super class method

I have two classes A, and B. Class B overrides the foo method of class A. Class B has a bar method where I want to call the foo method of the super class. What is the syntax for such a call?
class A
def foo
"hello"
end
end
class B < A
def foo
super + " world"
end
def bar
# how to call the `foo` method of the super class?
# something similar to
super.foo
end
end
For class methods I can call the methods up the inheritance chain by explicitly prefixing the class name. I wonder if there is a similar idiom for instance methods.
class P
def self.x
"x"
end
end
class Q < P
def self.x
super + " x"
end
def self.y
P.x
end
end
Edit
My use case is general. For a specific case I know I can use alias technique. This is a common feature in Java or C++, so I am curious to know if it is possible to do this without adding extra code.
In Ruby 2.2, you can use Method#super_method now
For example:
class B < A
def foo
super + " world"
end
def bar
method(:foo).super_method.call
end
end
Ref: https://bugs.ruby-lang.org/issues/9781#change-48164 and https://www.ruby-forum.com/topic/5356938
You can do:
def bar
self.class.superclass.instance_method(:foo).bind(self).call
end
In this particular case you can just alias :bar :foo before def foo in class B to rename the old foo to bar, but of course you can alias to any name you like and call it from that. This question has some alternative ways to do it further down the inheritance tree.
You can alias old_foo foo before redefining it to keep the old implementation around under a new name. (Technically it is possible to take a superclass's implementation and bind it to an instance of a subclass, but it's hacky, not at all idiomatic and probably pretty slow in most implementation to boot.)
Based on #Sony's answer.
In case when you want to call the method method on some my_object and it's already overriden somewhere several classes higher (like for the Net::HTTPRequest#method), instead of doing .superclass.superclass.superclass use the:
Object.instance_method(:method).bind(my_object)
Like this:
p Object.instance_method(:method).bind(request).call(:basic_auth).source_location

How to make a base class method non-overridable in ruby?

I have some base class A with a method that is not to be overridden.
class A
def dont_override_me
puts 'class A saying, "Thank you for not overriding me!"'
end
end
And another class B that extends A and tries to override the dont_override_me method.
class B < A
def dont_override_me
puts 'class B saying, "This is my implementation!"'
end
end
If I instantiate B and call dont_override_me, class B's instance method will be called.
b = B.new
b.dont_override_me # => class B saying, "This is my implementation!"
This is because of ruby's properties. Understandable.
However, how do I force the base class method dont_override_me to be non-overridable by it's derived classes? I could not find a keyword like final in java for ruby. In C++, the base class methods can be made non-virtual so that they become non-overridable by the derived classes. How do I achieve this in ruby?
You can do it, by hooking the change event and changing it back, but it seems a bit smelly to me:
http://scie.nti.st/2008/9/17/making-methods-immutable-in-ruby
It's one of those things that sort of defines Ruby, so fighting against it seems a little pointless imo. If someone redefines something so it breaks horribly.. that's their problem ;-)
Here's a way to do it:
http://www.thesorensens.org/2006/10/06/final-methods-in-ruby-prevent-method-override/
This has also been packaged into a gem called "finalizer" (gem install finalizer)
This makes use of the method_added callback and compares the new method name with a list of methods that you wish to make final.
I recommend:
class A #This is just as you've already defined it.
def dont_override_me
puts 'class A saying, "Thank you for not overriding me!"'
end
end
module BehaviorForB
def dont_override_me
puts 'class B saying, "This is my implementation!"'
end
def greet
"Hello, Friend."
end
end
class B < A
include BehaviorForB
end
b = B.new
b.dont_override_me #=> class A saying, "Thank you for not overriding me!"
b.greet #=> Hello, Friend.
By keeping B's methods tucked away in an mixin, you get exactly what you desire. Any method of B's methods that are not already in A will be available. Methods that are already in A will not be overridden.
One way to prevent a method from being overridden by a subclass (but not recommend) :
class Class
def frozen_method(method)
if class_variable_defined?(:##__frozen_methods__)
add= class_variable_get(:##__frozen_methods__) | [method]
class_variable_set(:##__frozen_methods__,add)
else
class_variable_set(:##__frozen_methods__,[method])
end
class << self
def inherited(child)
def method_added(method)
if class_variable_get(:##__frozen_methods__).include? method
send(:remove_method, method)
error="Cannot change method #{method} because it's not overridde"
raise TypeError, error
end
end
end
end
end
end
class Foo
def hello
'hello'
end
def foo
'foo'
end
frozen_method :foo
end
class Bar < Foo
def foo
'new foo'
end
end
#=> TypeError: Cannot change method foo because it's not overridde
Bar.new.foo #=> 'foo'
Warning: this example is not complete. If you add frozen_method for a previously defined method in the subclass, when this method will be modified in the subclass, it will lose its implementation.

Resources