I can see two initial approaches, namely define a class to represent your key,value pair or just use a hash to represent each data item. The advantage of a separate class is that you can extend it in the future, if for example you wanted to provide the exact value in a chart where you were rounding to the nearest 100k.
The following code shows three classes which together will do what you want
class Chart
attr_accessor :title, :series
def initialize(title = nil, series = [])
@title, @series = title, series
end
def show
puts title
@series.each do |ser|
puts "\t#{ser.legend} (#{ser.units})"
ser.data.each do |item|
puts "\t\t#{item}"
end
end
end
end
class Series
attr_accessor :legend, :units, :data
def initialize(legend = nil, units = nil, data = [])
@legend, @units, @data = legend, units, data
end
end
class DataItem
attr_accessor :key, :value
def initialize(key, value)
@key, @value = key, value
end
def to_s
"#{key}, #{value}"
end
end
Running this as follows :-
c = Chart.new("Sweet sales by Quarter")
c.series << Series.new("Bon-Bons", "£000",
[ DataItem.new("Q1", 220),
DataItem.new("Q2", 280),
DataItem.new("Q3", 123),
DataItem.new("Q4", 200)]
)
c.series << Series.new("Humbugs", "£000",
[ DataItem.new("Q1", 213),
DataItem.new("Q2", 254),
DataItem.new("Q3", 189),
DataItem.new("Q4", 221)]
)
c.show
Produces the following output
Sweet sales by Quarter
Bon-Bons (£000)
Q1, 220
Q2, 280
Q3, 123
Q4, 200
Humbugs (£000)
Q1, 213
Q2, 254
Q3, 189
Q4, 221
If you wanted to take the Hash approach then you would no longer need the DataItem class and you could instantiate a new Series with code like this
c = Chart.new("Sweet sales by Quarter")
c.series << Series.new("Bon-Bons", "£000",
[ { "Q1" => 220}, {"Q2" => 280}, {"Q3" => 123}, {"Q4" => 200}]
)
The show method of Chart would then look like this
def show
puts title
@series.each do |ser|
puts "\t#{ser.legend} (#{ser.units})"
ser.data.each do |item|
item.each_pair {|key, value| puts "\t\t#{key}, #{value}" }
end
end
end