How can I force a subclass to implement a method in Ruby. There doesn't seem to be an abstract keyword in Ruby, which is the approach I would take in Java. Is there another more Ruby-like way to enforce abstract?
Abstract methods are supposed to be less useful in Ruby because it's not strongly statically typed.
However, this is what I do:
class AbstractThing
MESS = "SYSTEM ERROR: method missing"
def method_one; raise MESS; end
def method_two; raise MESS; end
end
class ConcreteThing < AbstractThing
def method_one
puts "hi"
end
end
a = ConcreteThing.new
a.method_two # -> raises error.
It rarely seems to be necessary, however.
I like the answer by pvandenberk, but I would improve it as follows:
module Canine # in Ruby, abstract classes are known as modules
def bark
fail NotImplementedError, "A canine class must be able to #bark!"
end
end
Now if you make a class belonging to Canine "abstract class" (ie. a class that has Canine module in its ancestors), it will complain if it is found that #bark method is not implemented:
class Dog
include Canine # make dog belong to Canine "abstract class"
end
Dog.new.bark # complains about #bark not being implemented
class Dog
def bark; "Bow wow!" end
end
# Now it's OK:
Dog.new.bark #=> "Bow wow!"
Note that since Ruby classes are not static, but always open to changes, Dog class itself cannot enforce existence of #bark methods, since it doesn't know when is it supposed to be finished. If you as a programmer do, it is up to you to test it at such time.
My preferred approach is similar but slightly different... I prefer it as follows, because it makes the code self-documenting, giving you something very similar to Smalltalk:
class AbstractThing
def method_one; raise "SubclassResponsibility" ; end
def method_two; raise "SubclassResponsibility" ; end
def non_abstract_method; method_one || method_two ; end
end
Some people will complain that this is less DRY, and insist on creating an exception subclass and/or put the "SubclassResponsibility" string in a constant, but IMHO you can dry things up to the point of being chafed, and that is not usually a good thing. E.g. if you have multiple abstract classes across your code base, where would you define the MESS string constant?!?
I like the use of a gem like abstract_method which gives a dsl rails style syntax abstract methods:
class AbstractClass
abstract_method :foo
end
class AbstractModule
abstract_method :bar
end
class ConcreteClass < AbstractClass
def foo
42
end
end
This code will not let you load the class if the methods 'foo', 'bar' and 'mate' are not defined in the inherited class.
It does not account for classes being defined across many files, but lets get honest do many of us actually define class methods across many files? I mean if you don't count mix-ins. (which this does account for)
def self.abstract(*methods_array)
##must_abstract ||= []
##must_abstract = Array(methods_array)
end
def self.inherited(child)
trace = TracePoint.new(:end) do |tp|
if tp.self == child #modules also trace end we only care about the class end
trace.disable
missing = ( Array(##must_abstract) - child.instance_methods(false) )
raise NotImplementedError, "#{child} must implement the following method(s) #{missing}" if missing.present?
end
end
trace.enable
end
abstract :foo
abstract :bar, :mate
If you want to have an error thrown when you create an instance of the class you could do the following
class AbstractClass
def self.new(args)
instance = allocate # make memory space for a new object
instance.send(:default_initialize, args)
instance.send(:initialize, args)
instance
end
#This is called whenever object created, regardless of whether 'initialize' is overridden
def default_initialize(args)
self.abstract_method #This will raise error upon object creation
end
private :default_initialize
def initialize(args)
# This can be overridden by new class
end
end
class NewClass < AbstractClass
end
NewClass.new #Throw error
Because the question is (focus on) "How can I force a subclass to implement a method in Ruby", so i think we can use TDD :D, for example: rspec shared example
shared_examples "MUST implement abstract method" do |method_sym|
it { is_expected.to respond_to(method_sym) }
end
describe Stack do
it_behaves_like "MUST implement abstract method", :push
it_behaves_like "MUST implement abstract method", :pop
end
Maybe Tests are better than Abstract :D , reference: http://morningcoffee.io/interfaces-in-ruby.html
Related
I apologize up front. I'm going to struggle articulating this question.
TL;DR - I have an object I'm using to call a method in the subclass. That method needs access to a method in a parent class (forcing inheritance...read below). I'm thinking this won't work because I'm instantiating the subclass, so the inheritance won't work right, but I'm not sure. I'm still seeking out documentation. Basically, the method in the parent class is not "seen" the way I'm doing this - NoMethodError is the exception.
I prefer DRY code, as most people do. I usually use compositing in lieu of inheritance in my code, but I think I'm at a point where if I want to keep this DRY, I have to use inheritance (though I could be wrong, so I'm open to suggestions), and so I'm trying it out, which leads me to this question.
Given the following Ruby "pseudo" code or example to kind of demonstrate what I'm trying to accomplish:
module SomeModule
class ParentClass
def initialize
end
def method_i_want_to_use(arg1, *args)
# does all the things
end
def self.method_i_want_to_use(arg1, *args)
arg = args.first unless args.empty?
self.class.method_i_want_to_use(arg1, arg)
end
end
end
And then in a different file, same module
module SomeModule
class SubClass < ParentClass
def initialize
end
# this isn't working
def my_other_method
# things get done and then
method_i_want_to_use(arg1, args) ## <<=== fails
end
end
end
Yet in another file
module SomeModule
class Thing
def initialize
#my_obj = SubClass.new
end
def my_method
#my_obj.my_other_method
end
end
end
So one important thing I missed. The method method_i_want_to_use is a method that is used all over the place in my code. It just so happens that in this one class, inheritance was NOT originally used because this class is basically atomic with the exception of this one method. So my problem is either I copy the method into this class and use it (but that kinda breaks the DRY principle sorta) or I find a way to share this method between classes.
This gets into OOP design pretty heavily and I am aware of that. One could ask: well, is the inheritance as it currently sits even relevant to the objects in question? Yes...and no. They can be. In short, principally, it works, but frankly, I don't like it. TBH, I almost prefer to just copy the method into the "subclass" and remove the inheritance and be done with it, but DRY -- unless I'm going a little too wild with DRY in this context and I kinda think I am.
Anyway, just curious what folks with more knowledge than I have for me on this. This really is the first time I've dabbled this deeply into inheritance. :)
I'd love pointers on how I can keep from implementing
There are two different methods here:
an instance method:
def method_i_want_to_use(arg1, *args)
# does all the things
end
and a class method:
def self.method_i_want_to_use(arg1, *args)
arg = args.first unless args.empty?
self.class.method_i_want_to_use(arg1, arg)
end
but what you probably want in this case is
def self.method_i_want_to_use(arg1, *args)
arg = args.first unless args.empty?
self.new.method_i_want_to_use(arg1, arg)
end
There are a few choices and it depends on what method_i_want_to_use is doing. Is it a separate thing? Then you can call it as a class method ParentClass.method_i_want_to_use inside the SubClass without inheritance.
Another way is to define it in a module and include it
include ModuleX
# and then in your code
method_i_want_to_use(...)
I'd use inheritance if you want to have some kind of common abstraction layer and you expect multiple subclasses to behave the same way. If the classes/objects that need to use method_i_want_to_use have different behaviours then inheritance is not the correct choice. Let's say you have a class that send a request to a 3rd party API and you have a class that does saves records to your db. For some reason you need to use the same piece of code (a method) in both cases, maybe to calculate some value. Using inheritance to include the method would be a mistake, because both classes have different behaviours.
Hope that helps.
After fixing some of the syntax errors and changing the call self.class.method_i_want_to_use to self.new.method_i_want_to_use as Adam also mentioned in his answer, this code seems to work fine.
I did not get any undefined methods until I tried to call SomeModule::ParentClass.method_i_want_to_use(3,4) and that was fixed by the change from class to new. Are you sure your undefined method error was not related to that?
module SomeModule
class ParentClass
def initialize
end
def method_i_want_to_use(arg1, *args)
# does all the things
puts "here #{arg1} , #{args}"
end
def self.method_i_want_to_use(arg1, *args)
arg = args.first unless args.empty?
self.new.method_i_want_to_use(arg1, arg)
end
end
end
module SomeModule
class SubClass < ParentClass
def initialize
end
# this isn't working
def my_other_method(arg1, arg2)
# things get done and then
method_i_want_to_use(arg1, arg2) ## <<=== fails
end
end
end
module SomeModule
class Thing
def initialize
#my_obj = SubClass.new
end
def my_method(arg1,arg2)
#my_obj.my_other_method(arg1, arg2)
end
end
end
SomeModule::Thing.new.my_method(1,2)
SomeModule::ParentClass.method_i_want_to_use(3,4)
prints:
here 1 , [2]
here 3 , [4]
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
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"
I am a Ruby starter. I found both of these are quite similar (in output), but i couldn't understand the difference in the below context. For example, I have a class
class Say
def self.hello
puts "hello"
end
end
and can be extended like this
class << Say
def hi
puts "hi"
end
end
and also like this
Say.class_eval do
def self.bye
puts "bye"
end
end
When should I use << and when class_eval?
class_eval doesn't really have anything to do with class << className.
A.class_eval do
...
end
is equivalent to
class A
...
end
with a few differences. class_eval uses a block (or a string, but ignoring that for the moment) which means it closes over the containing lexical scope. In other words you can use local variables from the surrounding scope. The common class block introduces a brand new scope. Likewise you can create the block and pass it to many different class_eval's, and the body of the block will be executed in the context of the class you are calling class_eval on.
class << className opens the singleton class of className, allowing you to define class methods.
class << A
def foo
...
end
end
Is the same as
def A.foo
...
end
Note that they are oly class methods if A happens to be a class (almost) all objects in ruby have singleton classes and you can define methods for them using either of those two syntaxes. The advantage of class << obj is mainly if you're defining many singleton methods in one go.
As already said class_eval has really not much to do with
class <<self
even if they seem to do the same thing in your example (while the effect is similar it does not do the same, there are subtle differences).
Here is another example where the usage of the second form is far more clearer:
class A
end
a = A.new
b = A.new
class <<b
def say_hi
puts "Hi !"
end
end
b.say_hi # will print "Hi !"
a.say_hi # will raise an undefined method
a and b are both objects of the same class A but we added a method to the metaclass of b so the method say_hi is only available to the b object.
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.