Abstract methods in ruby ( >= 2.2.0)... do they exist? [duplicate] - ruby

This question already has answers here:
Abstract Method in Ruby
(7 answers)
Closed 7 years ago.
I'm writing a base class for an interface.. I want all the inherited classes to implement a few methods, is there a way to make them?
I have a payment_method_base class that I will be inheriting from.
I want all my payment_method classes to implement the method kind() that will return a string say 'credit_card' or 'braintree' or 'paypal' or 'amazon_pay'...
Is there a way to make sure that classes that inherit from payment_method_base are forced to implement the method kind()
Keeping in mind that the creator of a new payment_method class may not know about these requirements before they create the class.
In java these are called abstract methods. I'm wondering if ruby has something like that? https://github.com/shuber/defined/blob/master/lib/defined.rb
---- Evolution
I am wondering if there have been fixes to the language that allow for abstract methods.
---- partial answer
This answer might be the clue to adding the hooks I need.
Is there a hook similar to Class#inherited that's triggered only after a Ruby class definition?
This doesn't quite work the way I expected it would. The call doesn't seem to be done at the right time. Even so it is how many gems handle it.
https://github.com/shuber/defined/blob/master/lib/defined.rb
SIMPLES ANSWER THAT I CAN'T SUBMIT BECAUSE THIS IS A REPEAT OF A QUESTION THAT HAD NO REAL ANSWER.
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

Ruby doesn't really implement anything like interfaces as it's against it's philosophy but if you really want to simulate interfaces you can use some gem, for example https://github.com/djberg96/interface.

There are no abstract methods in ruby.
I suppose you could implement a method like this, and I have seen it from time to time:
def some_method
raise "This method should be over-ridden by a sub-class"
end
If a sub-class neglects to implement that method -- it won't be caught at 'compile time', because that doesn't happen in ruby. But if someone tries to call that method, which hasn't been implemented, you'll get an exception raised.
Of course, if you hadn't put that method (that does nothign more than raise) in the "abstract" superclass, and it was called on a sub-class without the sub-class implementing it... you'd still get a NoMethodException raised anyway. So the "abstract" method implementation that does nothing more than raise doesn't add much. Maybe a documentation of intent.
I think the most ruby-like way to handle this would probably be to provide a test suite of some kind, that another developer implementing a sub-class can easily run against their sub-class. The test suite will complain if the sub-class hasn't implemented things it's supposed to -- and it can even go beyond method signatures, and make sure the semantics of the sub-class are as expected too (you can't do that with just method signatures in Java!). I haven't actually seen anyone do that though, but have often thought it would make sense.

Related

Understanding Ruby define_method with initialize

So, I'm currently learning about metaprogramming in Ruby and I want to fully understand what is happening behind the scenes.
I followed a tutorial where I included some of the methods in my own small project, an importer for CSV files and I have difficulties to wrap my hand around one of the methods used.
I know that the define_method method in Ruby exists to create methods "on the fly", which is great. Now, in the tutorial the method initialize to instantiate an object from a class is defined with this method, so basically it looks like this:
class Foo
def self.define_initialize(attributes)
define_method(:initialize) do |*args|
attributes.zip(args) do |attribute, value|
instance_variable_set("##{attribute}", value)
end
end
end
end
Next, in an initializer of the other class first this method is called with Foo.define_initialize(attributes), where attributes are the header row from the CSV file like ["attr_1", "attr_2", ...], so the *args are not provided yet.
Then in the next step a loop loops over the the data:
#foos = data[1..-1].map do |d|
Foo.new(*d)
end
So here the *d get passed as the *args to the initialize method respectively to the block.
So, is it right that when Foo.define_initialize gets called, the method is just "built" for later calls to the class?
So I theoretically get a class which now has this method like:
def initialize(*args)
... do stuff
end
Because otherwise, it had to throw an exception like "missing arguments" or something - so, in other words, it just defines the method like the name implies.
I hope that I made my question clear enough, cause as a Rails developer coming from the "Rails magic" I would really like to understand what is happening behind the scenes in some cases :).
Thanks for any helpful reply!
Short answer, yes, long answer:
First, let's start explaining in a really (REALLY) simple way, how metaprogramming works on Ruby. In Ruby, the definition of anything is never close, that means that you can add, update, or delete the behavior of anything (really, almost anything) at any moment. So, if you want to add a method to Object class, you are allowed, same for delete or update.
In your example, you are doing nothing more than update or create the initialize method of a given class. Note that initialize is not mandatory, because ruby builds a default "blank" one for you if you didn't create one. You may think, "what happens if the initialize method already exist?" and the answer is "nothing". I mean, ruby is going to rewrite the initialize method again, and new Foo.new calls are going to call the new initialize.

Is this use of polymorphism misleading and therefore bad design?

If I have the following ruby module which implements a particular interface (apply in this case)
module FooApplier
def apply
foo
end
end
...and all other "Appliers" are classes, not modules, is it misleading to other engineers to pass FooApplier to receivers which expect the applyinterface?
Let's assume the application using FooApplier runs perfectly fine, but let's also assume that some other engineer didn't take the time to pour over every last byte of my code. If they decide to send something like .new to the FooApplier which somehow induces some subtle bug, is the onus on my design, or the engineer for making assumptions and neglecting to read my code?
The way your module is presented here, it won't work as a stand-in for a class. Let's look at a class first:
class BarApplier
def apply
bar
end
end
apply here is an instance method, so callable on instances of BarApplier, i.e. BarApplier.new.apply. This will not be possible for your module.
Unless of course apply was meant to be a class or module method, in which case your question was misleading since it then should be def self.apply.
But to answer the more general question, in a duck-typed language the sent messages are the interface. In my opinion the caller should make no assumptions about other methods being present. In your specific case, if apply is the only method in the "contract", assuming that the same entity also responds to new is invalid in my opinion.

What are empty-body methods used for in Ruby?

Currently reading a Ruby style guide and I came across an example:
def no_op; end
What is the purpose of empty body methods?
There are a number of reasons you might create an empty method:
Stub a method that you will fill in later.
Stub a method that a descendant class will override.
Ensure a class or object will #respond_to? a method without necessarily doing anything other than returning nil.
Undefine an inherited method's behavior while still allowing it to #respond_to? the message, as opposed to using undef foo on public methods and surprising callers.
There are possibly other reasons, too, but those are the ones that leapt to mind. Your mileage may vary.
There may be several reasons.
One case is when a class is expected to implement a specific interface (virtually speaking, given that in Ruby there are no interfaces), but in that specific class that method would not make sense. In this case, the method is left for consistency.
class Foo
def say
"foo"
end
end
class Bar
def say
"bar"
end
end
class Null
def say
end
end
In other cases, it is left as a temporary placeholder or reminder.
There are also cases where the method is left blank on purpose, as a hook for developers using that library. The method it is called somewhere at runtime, and developers using that library can override the blank method in order to execute some custom callback. This approach was used in the past by some Rails libraries.

Ruby YARD: documenting abstract methods implementations

I have a typical OO pattern: one base abstract class (that defines abstract methods) and several classes that implement these abstract methods in class-specific way.
I'm used to write documentation only once in abstract methods and then it automatically propagates to several concrete classes (at least it works the following way in Javadoc, in Scaladoc, in Doxygen), i.e. I don't need to repeat the same description in all concrete classes.
However, I couldn't find how to do such propagation in YARD. I've tried, for example:
# Some description of abstract class.
# #abstract
class AbstractClass
# Some method description.
# #return [Symbol] some return description
# #abstract
def do_something
raise AbstractMethodException.new
end
end
class ConcreteClass < AbstractClass
def do_something
puts "Real implementation here"
return :foo
end
end
What I get:
Code works as expected - i.e. throws AbstractMethodException is called in abstract class, does the job in concrete class
In YARD, AbstractClass is clearly defined as abstract, ConcreteClass is normal
Method description and return type is good in AbstractClass
Method is said to throw AbstractMethodException in AbstractClass
Method has no description at all and generic Object return type in ConcreteClass, there's not a single notice of that an abstract method exists in base class.
What I expect to get:
Method's description and return type are inherited (i.e. copied) to ConcreteClass from info at AbstractClass
Ideally, this method is specified in "inherited" or "implemented" section of ConcreteClass description, with some reference link from ConcreteClass#do_something to AbstractMethod#do_something.
Is it possible to do so?
I think the issue boils down to what you're trying to do. It looks like you're trying to implement an Interface in Ruby, which makes sense if you're coming from Java or .NET, but isn't really how Ruby developers tend to work.
Here is some info about how the typical thought on Interfaces in Ruby: What is java interface equivalent in Ruby?
That said, I understand what you're trying to do. If you don't want your AbstractClass to be implemented directly, but you want to define methods that can be used in a class that behaves like the AbstractClass stipulates (as in Design by Contract), then you probably want to use a Module. Modules work very well for keeping your code DRY, but they don't quite solve your problem related to documenting overridden methods. So, at this point I think you can reconsider how you approach documentation, or at least approach it in a more Ruby-ish way.
Inheritance in Ruby is really (generally speaking from my own experience) only used for a few reasons:
Reusable code and attributes
Default behaviors
Specialization
There are obviously other edge cases, but honestly this is what inheritance tends to be used for in Ruby. That doesn't mean what you're doing won't work or violates some rule, it just isn't typical in Ruby (or most dynamically typed languages). This atypical behavior is probably why YARD (and other Ruby doc generators) doesn't do what you expect. That said, creating an abstract class that only defines the methods that must exist in a subclass really gains you very little from a code perspective. Methods not defined will result in a NoMethodError exception being thrown anyway, and you could programmatically check if an object will respond to a method call (or any message for that matter) from whatever calls the method, using #respond_to?(:some_method) (or other reflective tools for getting meta stuff). It all comes back Ruby's use of Duck Typing.
For pure documentation, why document a method that you don't actually use? You shouldn't really care about the class of the object being sent or received from calling a method, just what those objects respond to. So don't bother creating your AbstractClass in the first place if it adds no real value here. If it contains methods you actually will call directly without overriding, then create a Module, document them there, and run $ yardoc --embed-mixins to include methods (and their descriptions) defined in mixed-in Modules. Otherwise, document methods where you actually implement them, as each implementation should be different (otherwise why re-implement it).
Here is how I would something similar to what you're doing:
# An awesome Module chock-full of reusable code
module Stuff
# A powerful method for doing things with stuff, mostly turning stuff into a Symbol
def do_stuff(thing)
if thing.kind_of?(String)
return thing.to_sym
else
return thing.to_s.to_sym
end
end
end
# Some description of the class
class ConcreteClass
include Stuff
# real (and only implementation)
def do_something
puts "Real implementation here"
return :foo
end
end
an_instance = ConcreteClass.new
an_instance.do_somthing # => :foo
# > Real implementation here
an_instance.do_stuff("bar") # => :bar
Running YARD (with --embed-mixins) will include the methods mixed-in from the Stuff module (along with their descriptions) and you now know that any object including the Stuff module will have the method you expect.
You may also want to look at Ruby Contracts, as it may be closer to what you're looking for to absolutely force methods to accept and return only the types of objects you want, but I'm not sure how that will play with YARD.
Not ideal, but you can still use the (see ParentClass#method) construct (documented here). Not ideal because you have to type this manually for every overriding method.
That being said, I'm no Yard specialist but given its especially customizable architecture, I'd be surprised that there would be no easy way to implement what you need just by extending Yard, somewhere in the Templates department I guess.

(J)Ruby - safe way to redefine core classes?

What is the safe way to redefine methods in core classes like File, String etc. I'm looking for implementing something similar to the Java Security Manager in (J)Ruby.
I'm looking for a way to redefine a method by first seeing which class/script has called this method and if that class/script belong to a list of some blacklisted classes (that I keep track of) I want to raise an exception, If the calling class belong to a non-blacklisted class then allow the operation. something like:
class String
alias_method :old_length, :length
def length
if(#nowHowDoIGetTheCallingClass)
raise "bad boy"
else
old_length
end
end
I tried this in JRuby, but this works only alternatively. One time the new length method is called and next time the old length method is called. I guess the alias doesn't work properly in JRuby! >.<
If something works sometimes, but not at other times, it's more likely to be your code that's the problem, not JRuby. Select isn't broken

Resources