-
Notifications
You must be signed in to change notification settings - Fork 20
MungerReport
This section uses the Munger::Data object data in the MungerData section.
Now that we have a data set in our Munger::Data object, we will format it as a report in a Munger::Report object. This includes sorting and grouping and aggregating and such. This is all in the abstract – then you pass it off to a MungerRender class to actually be rendered.
To start, simply feed in either the data object from the previous section, or an array of hashes or collection of AR objects.
report = Munger::Report.from_data(data)
The first thing you will notice in some of the previous examples is that the column order was random. In Munger, you have to specify the columns you want to see and what order they will go in. So without specifying anything, it will use all columns, but that is not fantastic, because it will choose them randomly and they can change each time – hashes don’t have ordered keys. You also don’t have to use every column.
Without formatting, you will get output like this:
|airdate | advert | rate | clicks | airtime | ------------------------------------------------- |2008-01-01 | Spot 1 | 20 | 301 | 15 | |2008-01-02 | Spot 1 | 6 | 199 | 30 | ...
However, if you run this :
report.columns([:advert, :airdate, :airtime, :rate])
|advert | airdate | airtime | rate |
|Spot 1 | 2008-01-01 | 15 | 20 |
|Spot 1 | 2008-01-02 | 30 | 6 |
…
Notice that we now control the order and the ‘clicks’ field is no longer shown.
You can also set prettier titles to be displayed like this:
report.columns(:advert => ‘Spot’, :airdate => ‘Air Date’, :airtime => ‘Airtime’, :rate => ‘Rate’)
|Spot | Rate | Air Date | Airtime |
-——————————————————-
|Spot 1 | 20 | 2008-01-01 | 15 |
|Spot 1 | 6 | 2008-01-02 | 30 |
…
You can sort the values :
report.sort(‘airtime’)
or
report.sort([‘airtime’, ‘rate’])
or
report.sort([['airtime', :desc], ['rate', :asc]])
|Spot | Rate | Air Date | Airtime | ---------------------------------------- |Spot 2 | 11 | 2008-01-03 | 90 | |Spot 3 | 8 | 2008-01-01 | 60 | |Spot 2 | 5 | 2008-01-01 | 30 | |Spot 1 | 6 | 2008-01-02 | 30 | |Spot 1 | 7 | 2008-01-03 | 30 | |Spot 2 | 10 | 2008-01-04 | 30 | |Spot 3 | 27 | 2008-01-02 | 30 | |Spot 2 | 14 | 2008-01-02 | 15 | |Spot 1 | 20 | 2008-01-01 | 15 | |Spot 1 | 22 | 2008-01-04 | 15 | |Spot 3 | 22 | 2008-01-03 | 15 |
You can subgroup like this:
report.subgroup('airtime')
|Spot | Rate | Air Date | Airtime | ---------------------------------------- |Spot 2 | 14 | 2008-01-02 | 15 | |Spot 1 | 20 | 2008-01-01 | 15 | |Spot 3 | 22 | 2008-01-03 | 15 | |Spot 1 | 22 | 2008-01-04 | 15 | | | | | | |Spot 2 | 5 | 2008-01-01 | 30 | |Spot 1 | 6 | 2008-01-02 | 30 | |Spot 1 | 7 | 2008-01-03 | 30 | |Spot 2 | 10 | 2008-01-04 | 30 | |Spot 3 | 27 | 2008-01-02 | 30 | | | | | | |Spot 3 | 8 | 2008-01-01 | 60 | | | | | | |Spot 2 | 11 | 2008-01-03 | 90 | | | | | |
And add aggregations like this:
report.aggregate(:sum => [:airtime, :rate])
|Spot | Rate | Air Date | Airtime | ---------------------------------------- |Spot 2 | 14 | 2008-01-02 | 15 | |Spot 1 | 20 | 2008-01-01 | 15 | |Spot 3 | 22 | 2008-01-03 | 15 | |Spot 1 | 22 | 2008-01-04 | 15 | | | 78 | | 60 | |Spot 2 | 5 | 2008-01-01 | 30 | |Spot 1 | 6 | 2008-01-02 | 30 | |Spot 1 | 7 | 2008-01-03 | 30 | |Spot 2 | 10 | 2008-01-04 | 30 | |Spot 3 | 27 | 2008-01-02 | 30 | | | 55 | | 150 | |Spot 3 | 8 | 2008-01-01 | 60 | | | 8 | | 60 | |Spot 2 | 11 | 2008-01-03 | 90 | | | 11 | | 90 | | | 152 | | 360 |
Which will automatically add sub-aggregations into each subgroup footer. You can also specify a custom Proc to do the aggregation calculations:
report.aggregate(Proc.new {|arr| arr.inject(0) {|total, i| i * i + (total - 30) }} => :airtime, :sum => :rate)
|Spot | Rate | Air Date | Airtime | ---------------------------------------- |Spot 2 | 14 | 2008-01-02 | 15 | |Spot 1 | 20 | 2008-01-01 | 15 | |Spot 3 | 22 | 2008-01-03 | 15 | |Spot 1 | 22 | 2008-01-04 | 15 | | | 78 | | 780 | |Spot 2 | 5 | 2008-01-01 | 30 | |Spot 1 | 6 | 2008-01-02 | 30 | |Spot 1 | 7 | 2008-01-03 | 30 | |Spot 2 | 10 | 2008-01-04 | 30 | |Spot 3 | 27 | 2008-01-02 | 30 | | | 55 | | 4350 | |Spot 3 | 8 | 2008-01-01 | 60 | | | 8 | | 3570 | |Spot 2 | 11 | 2008-01-03 | 90 | | | 11 | | 8070 | | | 152 | | 16770 |
Not that the example there makes much sense, but it does work.
Finally, you can mark cells and rows for special highlighting – basically, this means the html renderer will add named classes to your tr and td tags when it spits them out. Then you can provide your own stylesheets to make them look however you want.
If you want every cell that is below 30 to have a yellow highlight, you can run this:
report.style_cells('myRed') { |cell, row| (cell.to_i < 30) && (cell.to_i > 1) }
then add this to your css file:
.myRed { background: #e44; }
To get this:
Let’s say you only want to see when the rate is below 10, you can do this:
report.style_cells('myRed', :only => :rate) { |cell, row| (cell.to_i < 10) }
To get this:
You can do the same thing with report.style_rows()
, only the block only passes you a row.
To see how to actually get the pretty output we’ve been seeing, see the MungerRender section.