11

I read Growing Object-Oriented Software, Guided by Tests by Steve Freeman and Nat Pryce and was impressed very much. I want to adopt the ideas of this book in my Rails projects using RSpec, though its examples are written in Java.

A basic precept of this book is that we should mock interfaces instead of concrete classes. They say we can improve the application design by extracting interfaces and naming them.

But, Ruby doesn't have any syntax equivalent to Java's interface. How can I utilize their techniques for Rails projects?

UPDATE

For example, in the page 126 the authors introduced Auction interface in order to implement the bid method. Firstly, they mocked Auction.class to make the test pass, then they implemented an Auction class as anonymous inner class in the Main class. Finally, they extracted a new concrete class XMPPAuction from Main (page 131-132).

This incremental approach is the crux of this book in my opinion.

How can I adopt or imitate such a series of code transformation in the Ruby development?

Tsutomu
  • 4,848
  • 1
  • 46
  • 68
  • I replaced the word "concept" with "syntax" after reading the answers of Prakash and Andy. And removed the word "Unfortunately" to avoid an impression that I miss Java's `interface`. I love Ruby's *duck typing*. What I want is not an enforcement method in Java's manner. See the text after **UPDATE** for my intention. – Tsutomu Oct 29 '12 at 02:02

3 Answers3

6

Check out this previous Stack Overflow answer for a good explanation of interfaces in ruby.

Also, Practical Object-Oriented Design in Ruby is a book in similar vein as Growing Object Oriented Software book, but with ruby examples. Worth checking it out.

Community
  • 1
  • 1
Prakash Murthy
  • 12,923
  • 3
  • 46
  • 74
3

Since in Ruby, all things are duck-typed and the interface is simply the set of fields and methods that are publicly exposed you can do one or more of the following:

Test

Design your tests to test interfaces and name and comment your tests appropriately - then you can pass all of your "concrete implementations" of your "interface" through the same test suite. As long as your test suite covers your application's edge cases anything in your application that takes an instance of any of these concrete classes will be able to handle an instance of any of the other concrete classes.

Use base classes

Define a base class that all of your concrete classes will inherit from where all of the methods throw a NotImplemented error. This gives you a hierarchy that you can visualize - however, it does require extra classes and may encourage numerous is a tests in your production code rather than that code relying on has a.

Sean Vieira
  • 155,703
  • 32
  • 311
  • 293
  • 2
    You're right. I'd be a bit careful of using base classes to define interface. Partly because you might need class inheritance to share some implementation, and partly because you might want to implement multiple interfaces in a class. – Steve Freeman Oct 28 '12 at 09:19
2

You're right that Ruby does not have formal interfaces. Instead, interfaces are implicit in the messages that an object handles (see duck typing).

If you are still looking for a more formal way to "enforce" an interface in Ruby, consider writing a suite of automated unit tests that are green if an object conforms to the interface properly, and are red otherwise.

For examples, see ActiveModel::Lint::Tests and rspec's shared examples.

Andy Lindeman
  • 12,087
  • 4
  • 35
  • 36