Introduction to OpenStruct
Intro to OpenStruct
Last week I had a task to start working with some CSV data pulled in from the database. There was already existing code working with the data, so I needed to make sure whatever changes were applied, that they were backwards compatible. The data was an csv representation of an array. The current code was hard coded to go through the array in a fairly rigid process, so to add some flexibility, and allow better access the data in a controller, it was suggested to use OpenStruct.
First a quick overview on what is OpenStruct, it is a data structure that is similar to a hashe. It applies arbitrary attributes with accompanying values. It seems like magic, but it is just Ruby’s metaprogramming and it defines the methods on the classes themselves. A basic example of using OpenStruct on an object might be:
require "ostruct"
candy = OpenStruct.new
candy.name = "Snickers"
candy.type = "Chocolate"
candy.amount = 5
Then if I needed to call and figure out the candy name, or type, I can call a method on the object itself (instead of having to do the Ruby hash way which would’ve been candy[:name] # => “Snickers”)
candy.name
> "Snickers"
candy.type
> "Chocolate"
So the code went from using:
@csv = CSV.parse(parsed_text)
To the following with OpenStruct:
@csv = CSV.parse(parsed_text, headers: true).map { |row| OpenStruct.new(row.to_h) }
Making use of the csv data now went from:
@list = @csv[1..-1] || []
@count = @list.count
And now:
@list = @csv.map { |row| row.to_h.values } || []
@count = @csv.count
Accessing the values was much easier, but it is important to note with OpenStruct:
- It is not performant, which wasn’t something that needed to be kept in mind for this piece of code but if it is something that you do need to keep in mind, go for a hash or struct.
- OpenStruct != Struct , struct is similar to a custom created class that you don’t need to initialize or have any attr for. Struct is more performant, OpenStruct more flexible. Struct has to have the attributes defined, while it is dynamic with OpenStruct. For the ex. we have name, type and amount but couldn’t add on later an listing for populatarity.
candy = Struct.new(:name, :type, :amount)
snickers = candy.new("Snickers", "Chocolate", 5)
snickers.type
> "Snickers"