What is the Java equivalent in Ruby?

Can we expose interfaces in Ruby, like in java, and implement Ruby modules or classes to implement the methods defined by the interface.

One way is to use inheritance and the missing method to achieve the same, but is there any other more suitable approach?

+81
ruby interface
Dec 14 '10 at 8:40
source share
8 answers

Ruby has interfaces like any other language.

Note that you must be careful not to bring the concept of an interface, which is an abstract specification of responsibilities, guarantees, and block protocols, to the concept of an interface , which is a keyword in Java, the C # and VB.NET programming languages. In Ruby, we always use the former, but the latter simply does not exist.

It is very important to distinguish between the two. What is more important is Interface, not interface . interface tells you almost nothing useful. Nothing demonstrates this better than token interfaces in Java, which are interfaces with no members: just take a look at java.io.Serializable and java.lang.Cloneable ; these two interface mean very different things, but they have exactly the same signature.

So, if two interface , which mean different things, have the same signature, what exactly does interface mean, guaranteeing you?

Another good example:

 package java.util; interface List<E> implements Collection<E>, Iterable<E> { void add(int index, E element) throws UnsupportedOperationException, ClassCastException, NullPointerException, IllegalArgumentException, IndexOutOfBoundsException; } 

What is the java.util.List<E>.add ?

  • that the length of the collection does not decrease
  • that all the elements that were in the collection earlier are still there
  • that element is in the collection

And which one is really displayed in the interface ? Nobody! There is nothing in the interface that says that the Add method should even be added at all, it can simply remove an element from the collection.

This is a perfectly valid implementation of this interface :

 class MyCollection<E> implements java.util.List<E> { void add(int index, E element) throws UnsupportedOperationException, ClassCastException, NullPointerException, IllegalArgumentException, IndexOutOfBoundsException { remove(element); } } 

Another example: where in java.util.Set<E> does he really say that it is, you know, a collection? Nowhere! More precisely, in the documentation. In English.

In almost all cases of interfaces , with both Java and .NET, all relevant information is actually in the documents, not in the types. So, if types don't tell you anything interesting at all, why keep them at all? Why not just stick to the documentation? And that is exactly what Ruby does.

Please note that there are other languages ​​in which the interface can really be described in a meaningful way. However, these languages ​​usually do not call the construct that describes the interface " interface ", they call it type . In a language-dependent programming language, you can, for example, express properties that the sort function returns a collection of the same length as the original, that every element that is in the original is also in a sorted collection, and that before the smaller element is not a larger element appears.

So, in short: Ruby has no Java interface equivalent. However, it has the equivalent of a Java interface, and it is exactly the same as in Java: documentation.

In addition, as in Java, Acceptance Tests can also be used to specify interfaces.

In particular, in Ruby, an object’s interface is determined by what it can do, not what the class is, or what it mixes up with. module he mixes. Any object that has a << method can be attached. This is very useful in unit tests, where you can simply pass an Array or String instead of the more complex Logger , although Array and Logger do not share an explicit interface because they both have a method called << .

Another example is StringIO , which implements the same interface as IO , and therefore most of the File interface, but without sharing any common ancestor other than Object .

+85
Dec 14 '10 at 13:38
source share

Try using common rspec examples:

https://www.relishapp.com/rspec/rspec-core/v/3-5/docs/example-groups/shared-examples

You write a specification for your interface, and then put one line in each developer specification, for example.

 it_behaves_like "my interface" 

Full example:

 RSpec.shared_examples "a collection" do describe "#size" do it "returns number of elements" do collection = described_class.new([7, 2, 4]) expect(collection.size).to eq(3) end end end RSpec.describe Array do it_behaves_like "a collection" end RSpec.describe Set do it_behaves_like "a collection" end 
+32
Mar 22 2018-12-22T00:
source share

Can we provide interfaces in Ruby, like in java, and provide Ruby modules or classes for implementing methods defined by the interface.

Ruby does not have this functionality. In principle, they are not needed, since Ruby uses the so-called duck set .

There are several approaches you can take.

Record implementations that throw exceptions; if a subclass tries to use an unrealized method, it will fail

 class CollectionInterface def add(something) raise 'not implemented' end end 

Along with the above, you should write test code that ensures the execution of your contracts (that another message here incorrectly calls the interface)

If you find that you are writing invalid methods, such as, for example, all this time, write a helper module that captures this

 module Interface def method(name) define_method(name) { |*args| raise "interface method #{name} not implemented" } end end class Collection extend Interface method :add method :remove end 

Now connect the above with the Ruby modules and you are close to what you want ...

 module Interface def method(name) define_method(name) { |*args| raise "interface method #{name} not implemented" } end end module Collection extend Interface method :add method :remove end col = Collection.new # <-- fails, as it should 

And then you can do

 class MyCollection include Collection def add(thing) puts "Adding #{thing}" end end c1 = MyCollection.new c1.add(1) # <-- output 'Adding 1' c1.remove(1) # <-- fails with not implemented 

We emphasize once again: this is rudimentary, since everything in Ruby happens at runtime; no compile time check. If you compare this to testing, then you should be able to pick up the bugs. Moreover, if you take the above, you can probably write an interface that first checks the class when an object of this class is created; making your tests as simple as calling MyCollection.new ... yes, above :)

+21
Jul 16 '14 at 7:09
source share

As everyone said, there is no interface system for ruby. But through introspection, you can easily implement it yourself. Here is a simple example that can be improved in many ways to help you get started:

 class Object def interface(method_hash) obj = new method_hash.each do |k,v| if !obj.respond_to?(k) || !((instance_method(k).arity+1)*-1) raise NotImplementedError, "#{obj.class} must implement the method #{k} receiving #{v} parameters" end end end end class Person def work(one,two,three) one + two + three end def sleep end interface({:work => 3, :sleep => 0}) end 

Removing one of the methods declared on Person or changing its number will raise a NotImplementedError .

+8
Oct. 16 '13 at 14:40
source share

There are no such things as interfaces in Java. But there are other things that you can enjoy in ruby.

If you want to implement some types and interface - so that objects can be checked to see if they have any methods / messages that you require, you can take a look at rubycontracts . It defines a mechanism similar to PyProtocols . The ruby ​​type checking blog is here .

These approaches are not live projects, although at first it seems that the goal seems to be pleasant, it seems that most ruby ​​developers can live without strict type checking. But the flexibility of rubies allows for type checking.

If you want to extend objects or classes (the same thing in a ruby) with certain types of behavior or have a ruby ​​multiple inheritance method, use the include or extend mechanism. With include you can include methods from another class or module in an object. With extend you can add behavior to a class so that its instances have added methods. This was a very short explanation.

I believe that the best way to enable the Java interface is to understand the ruby ​​object model (see, for example, Dave Thomas's lectures ). You will probably forget about Java interfaces. Or you have an exceptional application on your schedule.

+4
Dec 14 2018-10-14
source share

As you can see from many answers, there is no way in Ruby to force a class to implement a particular method, inheriting from the class, including a module or something like that. The reason for this is probably the prevalence of TDD in the Ruby community, which is another way of defining an interface - tests not only determine method signatures, but also behavior. Thus, if you want to implement another class that implements some already defined interface, you must make sure that all tests are passed.

Typically, tests are defined in isolation using mocks and stubs. But there are also tools like Bogus , which allows you to define contract tests. Such tests not only determine the behavior of the "primary" class, but also verify that there are plastered methods in the interacting classes.

If you are really concerned about interfaces in Ruby, I would recommend using a testing platform that implements contract testing.

+4
May 15, '15 at 20:20
source share

All the examples here are interesting, but there isn’t enough verification of the Interface contract, I mean, if you want your object to implement all the definitions of interface methods, and only this you cannot. Therefore, I offer you a simple simple example (you can confidently improve it) to make sure that you have exactly what you expect from your interface (contract).

view your interface with specific methods such as

 class FooInterface class NotDefinedMethod < StandardError; end REQUIRED_METHODS = %i(foo).freeze def initialize(object) @object = object ensure_method_are_defined! end def method_missing(method, *args, &block) ensure_asking_for_defined_method!(method) @object.public_send(method, *args, &block) end private def ensure_method_are_defined! REQUIRED_METHODS.each do |method| if !@object.respond_to?(method) raise NotImplementedError, "#{@object.class} must implement the method #{method}" end end end def ensure_asking_for_defined_method!(method) unless REQUIRED_METHODS.include?(method) raise NotDefinedMethod, "#{method} doesn't belong to Interface definition" end end end 

Then you can write an object with at least an Interface contract:

 class FooImplementation def foo puts('foo') end def bar puts('bar') end end 

You can safely call your object through your interface to make sure that you define the interface exactly

 # > FooInterface.new(FooImplementation.new).foo # => foo # > FooInterface.new(FooImplementation.new).bar # => FooInterface::NotDefinedMethod: bar doesn't belong to Interface definition 

And you can also ensure that your object implements all the definitions of your interface.

 class BadFooImplementation end # > FooInterface.new(BadFooImplementation.new) # => NotImplementedError: BadFooImplementation must implement the method foo 
+3
May 28 '15 at 15:04
source share

I realized that too often I used the "Error not implemented" template to check the security of objects that I need for specific behavior. Ended up writing a gem, which basically allows you to use this interface:

 require 'playable' class Instrument implements Playable end Instrument.new #will throw: Interface::Error::NotImplementedError: Expected Instrument to implement play for interface Playable 

It does not check method arguments . It has version 0.2.0 version. More detailed example at https://github.com/bluegod/rint

0
Nov 13 '15 at 19:26
source share



All Articles