[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
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
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
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
---ruby
class Beer < Valuable
hasvalue :bornon, :parsewith => Proc.new {|value| value.isa?(String) ? Time.parse(value) : value }
end
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
end
I like this alot, but it's my second-favorite to option 1, just leave it.