I am currently trying to implement a model to simplify graphical chart creation. However, one of the attributes must be an array of attributes. For example:
"Chart_Series" has a "name" which would be a string and a data field which would be separated by dates which is an array of arrays [[Date1, Value1],[Date2,Value2],[Date3,Value3].
The purpose is to create an array of "Chart_Series" so as to call upon something like:
for series in @chart_series
series.name
for data in series.data
data.[Date, Value]
end
end
which would do something along the lines of:
Name1
Date1, Value1
Date2, Value 2,
Date3, Value 3,
Date4, Value 4,
Name2
Date1, Value 1,
Date2, Value 2,
Date3, Value 3,
Date4, Value 4,
This is not exactly the code desired.. I am interested in simply generating the model which could do something like this. Any help is appreciated
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
Assuming you intend to use a relational database backend with ActiveRecord then I beleive you need (at least) two models. Something like this:
class Chart < ActiveRecord::Base
has_many :data_points
end
class DataPoint < ActiveRecord::Base
belongs_to :chart
end
Your Chart
model would have the name
attribute and the DataPoint
model would have the date
and value
attributes.
Then you can reference your data points, as an association, like this:
@chart.data_points
so it looks like an array attribute, even though it is an association with another model
You try something like this
Say you have a class called User and you need to generate its attributes dynamically, you can do this like this,
class User
User.class_exec{
%w[name age address].each{|i|
attr_accessor i
}
}
end
this will create a User class with attributes
name, age and address
and you can use this as
a = User.new
a.name = "sameera"
a.age = "29"
a.address = "home town"
puts a.inspect
hope this helps
cheers
sameera