DEV Community

Flexible Ruby Value Object Initialisation

MetaDave πŸ‡ͺπŸ‡Ί on January 21, 2019

Problem Value objects in Ruby are lovely things, and invaluable in a complex application. But one issue that always seems to trip me...
Collapse
 
philnash profile image
Phil Nash

Nice use of refinements. I've not seen them around much, but this is a good example of how they can really clean up an approach.

Collapse
 
databasesponge profile image
MetaDave πŸ‡ͺπŸ‡Ί • Edited

Thanks Phil. I like the way they put the Ruby core objects on a level playing field with your own application objects, and let them add the behaviour you want.

Having said that, I'd probably draw a line at doing anything like:

module EasyFinder
  refine Integer do
    def to_book
      Book.find(self)
    end
  end

  refine String do
    def to_book
      Book.find(self.to_i)
    end
  end
end

... if I thought anyone was ever going to see my code.

I like the semantics, but it's a bit "out there".

 
databasesponge profile image
MetaDave πŸ‡ͺπŸ‡Ί

In itself, adding responses to a class clearly does not constitute type checking, it is simply "adding responses to a class".

So are you saying that needing to reference the module that adds the behaviour constitutes a form of type checking?

 
databasesponge profile image
MetaDave πŸ‡ͺπŸ‡Ί

Refinements depend on the type

Everything in some way depends on the type, because the type defines the messages that can be received and the responses. That is not type checking, though, that is just code.

Other types, no matter whether they respond to / implement this functionality are rejected

If they respond to the correct message then they are not rejected by my ISBN class, because my ISBN class is not type checking. The refinements are just a way of adding the required responses that is safer than monkey patching, but ultimately they just define behaviour.

I would be keen on hearing other opinions, though.

Collapse
 
ben profile image
Ben Halpern

Super enlightening Ruby post πŸ‘Œ

 
databasesponge profile image
MetaDave πŸ‡ͺπŸ‡Ί

Yes, it is a duck check, but I don't want a type check or a duck check. Or any kind of check, really.

What I'm describing is how to achieve the aim of not doing those checks. If that is not an aim that someone shares then they of course are free to implement a different methodology.

Collapse
 
databasesponge profile image
MetaDave πŸ‡ͺπŸ‡Ί

Indeed, Ruby does conversions very well, as you show in the first code sample.

I do like case, but again it's a type check. I'd rather avoid them if I can. It's good code that, though.

 
databasesponge profile image
MetaDave πŸ‡ͺπŸ‡Ί

I don't see it as anything other than enabling 100% duck typing in the application. I'm ensuring that the application depends only on the ability to respond, not on the underlying object type.