Reputation: 9028
I often need to convert some kind of data into other data (usually strings, arrays and hashes). For example:
"a;simple;list"
expected_output
: [ { content: "a", length: 1 }, { content: "simple", length: 6 }, { content: "list", length: 4 } ]
This can be done by:
input.split(";").map{|s| { content: s, length: s.size } }
but I want to use conversion at different places. So I need to provide encapsulated logic to achieve and reuse this. Three ways pop into mind:
Use a helper method (put a single method into a module):
module Converter
extend self
def convert(input)
input.split(";").map{|s| { content: s, length: s.size } }
end
end
module Caller
Converter.convert(input)
end
Use a dedicated class with parameters:
class Converter
def initialize(input)
@input = input
end
def convert
@input.split(";").map{|s| { content: s, length: s.size } }
end
end
module Caller
Converter.new(input).convert
end
Use refinements, using monkey patching to create a method on the data object but letting a caller decide if it should be included.
module Converter
refine String do
def convert
self.split(";").map{|s| { content: s, length: s.size } }
end
end
end
module Caller
using Converter
input.convert
end
I'm not satisfied with any of them, but the third option seems the cleanest because that is usually what you would do if you deal with custom objects. But it also feels wrong because it's monkey patching light. What are your thoughts?
Upvotes: 2
Views: 500
Reputation: 5852
It's great that you are approaching this from an OO perspective.
I like a variation on your second suggestion, with a small difference-- use an object, but don't instantiate it.
class StringConverter
def self.to_size_hash(string)
string.split(';').map { |s| { content: s, length: s.size } }
end
end
2.2.2 :001 > StringConverter.to_size_hash "a;simple;list"
=> [{:content=>"a", :length=>1}, {:content=>"simple", :length=>6}, {:content=>"list", :length=>4}]
As long as this class is only going to do one thing, once, I can't think of a good reason to persist it in memory.
The benefits of this approach are that you're encapsulating the logic in the StringConverter
class, without writing another module (the first option in your question), or changing the expected behavior of the String
class (the third option). It's a dedicated class for this transformation that you can use anywhere you need it.
Upvotes: 1