[Valuable] parsing attributes

By: Johnathon Wright on: May 17, 2010

This post is me thinking 'out loud' about how to add custom parsing "ruby gem valuable":http://valuable.mustmodify.com

In the past I ran into quite a few situations where I wanted to parse / process / format certain attributes as they came in. There seemed to be a lull in that so I hadn't implemented it, but now I find myself wanting it again. I'm looking at several ways to implement it and I'm not sure which one(s) are best.

Here's how you can do it now:

---ruby class Beer < Valuable

hasvalue :bornon, :klass => Time

def bornon=(value) attributes[:bornon] = value.is_a?(String) ? Time.parse(value) : value end


I like the simplicity here. No extra code is added to valuable, but it's still readable. I don't like the fact that you have to know to set it to attributes[:born_on]. That should be abstracted.

You could always call super...

option one: make no changes, call super

---ruby class Beer < Valuable

hasvalue :bornon, :klass => Time

def bornon=(value) super( value.isa?(String) ? Time.parse(value) : value ) end


I initially didn't like this because I had an idea in my head of some code I wanted to add, not making changes is really growing on me. Could I just update the documentation and release a new version with 'new functionality'? :)

The code generated by valuable is absent... but looking at the generated constructor, really, we're not missing anything.

It's almost pointless to even have :klass => Time as Time.new(...) will result in 'ArgumentError: wrong number of arguments (1 for 0)', though it does provide a sort of executable comment...

option two: Indicate the method to use to parse.

---ruby class Beer < Valuable

hasvalue :bornon, :parsewith => :bornon_parser

def bornonparser( value ) value.is_a?(String) ? Time.parse(value) : value end


I'm not fond of this. Should it be an instance or class-level method? I guess instance makes sense, but then I almost feel like it should be reading attributes instead of having a value passed in. If static, well, that makes even less sense as instance-level setters would be calling class-level parsers... enh. I guess it's not a travesty, but not my favorite.

option three: provide a proc to the has_value method


class Beer < Valuable

hasvalue :bornon, :parsewith => Proc.new {|value| value.isa?(String) ? Time.parse(value) : value }


This starts to seem cluttered.

option four: separately provide parsing that would be added to the setter:

---ruby class Beer < Valuable

hasvalue :bornon

parse( :bornon ) do |value| value.isa?(String) ? Time.parse(value) : value end


I like this alot, but it's my second-favorite to option 1, just leave it.


Just checking that you are human. What would be the result of this code?

a = 3*(4/2); b = 1; a+b