Class: Crosstab::Crosstab
Instance Method Summary collapse
-
#banner(&block) ⇒ Object
Creates a new Crosstab::Banner.
-
#calculate ⇒ Object
Runs the calculations.
-
#data_source(value = nil) ⇒ Object
DSL accessor for the data_source attribute which normally contains an empty array or an array of hashes.
-
#initialize(&block) ⇒ Crosstab
constructor
Pass in a block and we’ll execute it within the context of this class.
-
#table(&block) ⇒ Object
Creates a new Crosstab::Table and appends it to tables.
-
#tables ⇒ Object
Returns the array of tables for this Crosstab.
- #to_s ⇒ Object
Methods inherited from Generic
#printed?, #qualification, #qualifies?, #title
Constructor Details
#initialize(&block) ⇒ Crosstab
Pass in a block and we’ll execute it within the context of this class.
Example:
my_crosstab = Crosstab.new do
do
column "Total"
column "18-34", :b => 1
column "35-54", :b => 2
end
table do
row "Male", :a => 1
row "Female", :a => 2
end
end
19 20 21 |
# File 'lib/crosstab/crosstab.rb', line 19 def initialize(&block) instance_eval(&block) if block end |
Instance Method Details
#banner(&block) ⇒ Object
Creates a new Crosstab::Banner
Example:
# First let's look at the default banner with its total column:
#=> Crosstab::Banner
# banner.columns.first.title
#=> "Total"
# Now let's create a new banner.
do
column "Male", :a => 1
column "Female", :a => 2
end
.columns.first.title
#=> "Male"
.columns.last.title
#=> "Female"
72 73 74 75 76 77 78 |
# File 'lib/crosstab/crosstab.rb', line 72 def (&block) if block @banner = Crosstab::Banner.new(&block) else @banner ||= Crosstab::Banner.new end end |
#calculate ⇒ Object
Runs the calculations.
Warning: This is a CPU-heavy method. If you’re working with a large record size, processing time can explode out of control. You can expect this routine to process 1,000,000+ transactions a second. What’s a transaction? It’s just about 1 record x 1 row x 1 column.
Some examples: 1 second => N=1,000 * 100 rows * 10 columns
1 second => N=100,000 * 10 rows * 1 column
16.6 minutes => N=1,000,000 * 100 rows * 10 columns
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/crosstab/crosstab.rb', line 122 def calculate # pre-calculate which interviews belong in the banner run working_records = data_source.select do |i| self.qualifies? i and .qualifies? i end # pre-calculate which interviews belong in each column .columns.each do |column| column.records(working_records.select { |i| column.qualifies? i }) end tables.each do |table| .columns.each_with_index do |column, column_index| # pre-calculate which interviews belong in this table table_records = column.records.select do |i| table.qualifies? i end # do the actual stub calculations table.rows.each do |row| # if this row is part of a group, and the group hasn't already been calculated for this cell... if row.group and row.group.cells[column_index].nil? row.group.cells[column_index] = Crosstab::Cell.new row.group.cells[column_index].base table_records.length row.group.cells[column_index].frequency table_records.select { |i| row.group.qualifies? i }.length end # The actual normal row calculations row.cells[column_index] ||= Crosstab::Cell.new row.cells[column_index].base table_records.length row.cells[column_index].frequency table_records.select { |i| row.qualifies? i }.length end end end end |
#data_source(value = nil) ⇒ Object
DSL accessor for the data_source attribute which normally contains an empty array or an array of hashes. To install your own data, just pass in an array of hashes as the argument.
Example:
my_crosstab = Crosstab::Crosstab.new
my_crosstab.data_source
# => []
my_crosstab.data_source [{:a => 1, :b => 2},
{:a => 2, :b => 2}]
my_crosstab.data_source
# => [{:a => 1, :b => 2},{:a => 2, :b => 2}]
41 42 43 44 45 46 47 |
# File 'lib/crosstab/crosstab.rb', line 41 def data_source(value=nil) if value @data_source = value else @data_source ||= [] end end |
#table(&block) ⇒ Object
Creates a new Crosstab::Table and appends it to tables
Example:
my_crosstab = Crosstab.new
my_crosstab.tables
# => []
my_crosstab.table do
title "Q.B Age"
row "18-34", :b => 1
row "35-54", :b => 2
end
my_crosstab.tables
# => [Crosstab::Table]
my_crosstab.tables.first.rows.first.title
#=> "18-34"
my_crosstab.tables.first.rows.last.title
#=> "35-54"
108 109 110 |
# File 'lib/crosstab/crosstab.rb', line 108 def table(&block) tables << Crosstab::Table.new(&block) end |
#tables ⇒ Object
Returns the array of tables for this Crosstab.
81 82 83 |
# File 'lib/crosstab/crosstab.rb', line 81 def tables @tables ||= [] end |
#to_s ⇒ Object
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/crosstab/crosstab.rb', line 158 def to_s calculate widths = { :hyphenation_min => 3, :row_header => 29, # Width of the title of each row :row_indent => 2, # Indent 2 spaces if the row is part of a group :column => 7, :divider => 2 } letter_lookup = {} (1..26).each { |x| letter_lookup[x] = (x+64).chr } format_strings = { :group_headers => " " * widths[:row_header] + " " * widths[:divider] + (.columns.collect { |x| x.group }.to_freq_chart.collect { |x| (x[1].nil? ? " " : "|") * (widths[:column] * x[0] + widths[:divider] * (x[0] - 1)) + " " * widths[:divider]}.join), :group_border => " " * widths[:row_header] + " " * widths[:divider] + (.columns.collect { |x| x.group }.to_freq_chart.collect { |x| (x[1].nil? ? " " : "-") * (widths[:column] * x[0] + widths[:divider] * (x[0] - 1)) + " " * widths[:divider]}.join), :column_headers => " " * widths[:row_header] + " " * widths[:divider] + ("|" * widths[:column] + " " * widths[:divider]) * .columns.length, :column_border => " " * widths[:row_header] + " " * widths[:divider] + ("-" * widths[:column] + " " * widths[:divider]) * .columns.length, :baseline => "[" * widths[:row_header] + " " * widths[:divider] + ("]" * widths[:column] + " " * widths[:divider]) * .columns.length, :rows => "[" * widths[:row_header] + " " * widths[:divider] + ("]" * widths[:column] + " " * widths[:divider]) * .columns.length, :indented_rows => " " * widths[:row_indent] + "[" * (widths[:row_header] - widths[:row_indent]) + " " * widths[:divider] + ("]" * widths[:column] + " " * widths[:divider]) * .columns.length, :underline_row => "_" * widths[:row_header], :line_break => "", :page_break => "-" * 72 } r = Text::Reform.new r.min_break = widths[:hyphenation_min] report_stack = [] tables.each_with_index do |tbl, i| # Table Header report_stack << "Table #{i + 1}" report_stack << tbl.title.dup if tbl.title # Group headers if .columns.any? { |x| x.group } report_stack << format_strings[:group_headers] .columns.each do |col| if col.group unless report_stack.last == col.group.title report_stack << col.group.title.dup end end end report_stack << format_strings[:group_border] end # Column Headers report_stack << format_strings[:column_headers] .columns.each_with_index do |col, col_index| report_stack << [ col.title.dup, "(#{letter_lookup[col_index + 1]})"] end report_stack << format_strings[:column_border] # Baseline report_stack << format_strings[:baseline] report_stack << "(BASE)" report_stack += tbl.rows[0].cells.collect { |x| x.base } report_stack << format_strings[:line_break] # Each row tbl.rows.each do |row| if row.group and not row.group.printed? row.group.printed? true # Set to true so it won't be printed again report_stack << format_strings[:rows] report_stack << [row.group.title.dup, "-" * widths[:row_header]] report_stack += row.group.cells.collect { |cell| cell.result } report_stack << format_strings[:line_break] end report_stack << format_strings[row.group ? :indented_rows : :rows] # if it's part of a group then indent it. report_stack << row.title.dup report_stack += row.cells.collect { |cell| cell.result } report_stack << format_strings[:line_break] end report_stack << format_strings[:page_break] end r.format(*report_stack) end |