Skip to content

Commit

Permalink
Minor ruby style changes
Browse files Browse the repository at this point in the history
  • Loading branch information
snusnu committed Apr 12, 2010
1 parent c0cecbb commit bd7df13
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 47 deletions.
62 changes: 30 additions & 32 deletions lib/data_table.rb
@@ -1,16 +1,16 @@
require 'fastercsv'

class DataTable

class ColumnAlreadyExists < StandardError ; end
class ColumnNotFound < StandardError ; end
class ColumnNotFound < StandardError ; end

INFINITY = 1.0/0
INFINITY = 1.0 / 0

class Aggregators
SUM = lambda do |key, rows|
result = 0.0
rows.each { |r| result += r[key] }
result

SUM = lambda do |key, rows|
rows.inject(0.0) { |sum, row| sum += row[key] }
end

MIN = lambda do |key, rows|
Expand All @@ -24,26 +24,25 @@ class Aggregators
rows.each { |r| result = r[key] if r[key] > result }
result
end

end

class Column
attr_accessor :key
attr_accessor :header
attr_accessor :transformer

attr_accessor :key, :header, :transformer

def initialize(key, header, transformer)
@key = key
@header = header
@transformer = transformer
@key, @header, @transformer = key, header, transformer
end

end

class Row

attr_accessor :cells

def initialize(table)
@table = table
@cells = {}
@table, @cells = table, {}
end

# get cell
Expand All @@ -53,38 +52,38 @@ def [](key)

# set cell
def []=(key, value)
raise ColumnNotFound unless @table.columns.has_key?(key)
raise ColumnNotFound unless @table.columns.key?(key)
@cells[key] = value
end

end
attr_accessor :columns
attr_accessor :rows


attr_accessor :rows, :columns

def initialize
@columns = {}
@column_keys = [] # used to memorize the order of columns
@rows = []
@rows, @columns = [], {}
@column_keys = [] # used to memorize the order of columns
end

def add_column(key, header, transformer = nil)
raise ColumnAlreadyExists if @columns.has_key?(key)
raise ColumnAlreadyExists if @columns.key?(key)
@column_keys << key
@columns[key] = Column.new(key, header, transformer)
end

def build_rows(items)
items.each do |item|
row = Row.new(self)
@columns.each do |key, col|
columns.each do |key, col|
if col.transformer
row[key] = col.transformer.call(item)
elsif item.respond_to?(key)
row[key] = item.send(key)
end
end
yield(row, item) if block_given?
@rows << row
rows << row
end
end

Expand All @@ -103,19 +102,19 @@ def aggregate(key, rows, aggregators, group_key)

# yields a grouped DataTable object
def group_by(key, aggregators, group_key = lambda {|x| x })
result = DataTable.new
result = self.class.new
my_key = key
groups = {}

@rows.each do |row|
rows.each do |row|
idx = group_key.call(row[key])
groups[idx] = groups[idx].to_a << row
end

# copy implicitly selected colums from original data table
result.add_column(key, @columns[key].header)
result.add_column(key, columns[key].header)
aggregators.each_key do |key|
result.add_column(key, @columns[key].header)
result.add_column(key, columns[key].header)
end

groups.each_value do |group|
Expand All @@ -130,13 +129,13 @@ def render_csv(options)
# Add headers
headers = []
@column_keys.each do |key|
headers << @columns[key].header
headers << columns[key].header
end

csv << headers

# Add data rows
@rows.each do |row|
rows.each do |row|
row_data = []
@column_keys.each do |key|
row_data << row[key]
Expand All @@ -146,6 +145,5 @@ def render_csv(options)

end
end
end


end
37 changes: 22 additions & 15 deletions test/test_data_table.rb
@@ -1,6 +1,7 @@
require 'helper'

class TestDataTable < Test::Unit::TestCase

context "A DataTable instance" do
setup do

Expand Down Expand Up @@ -29,36 +30,42 @@ def initialize(articlenum, name, group, ordered, quantity, price)
OrderPosition.new("DTJA6181", "R2DX", "BB", Date.new(2009, 10, 4), 1, 200.0 ),
OrderPosition.new("DTJA6181", "R2DX", "BB", Date.new(2009, 10, 4), 1, 20.0 )
]

end

should "work properly" do

t = DataTable.new

# variant 1: implicit method lookup
t.add_column(:articlenum, "Articlenum")
t.add_column(:name, "Product Name")
t.add_column(:ordered, "Datum")
t.add_column(:group, "Product Group")
# variant 2: explicit transformer function that yields an item of your collection
t.add_column(:amount, "Amount", lambda { |p| p.quantity*p.price })
# variant 3: explicit row modification (see build_rows!)
# Variant 1: implicit method lookup

t.add_column :articlenum, "Articlenum"
t.add_column :name, "Product Name"
t.add_column :ordered, "Datum"
t.add_column :group, "Product Group"

# Variant 2: explicit transformer function that yields an item of your collection

t.add_column(:amount, "Amount", lambda { |p| p.quantity*p.price })

# Variant 3: explicit row modification (see build_rows)

t.add_column(:doubled_price, "Doubled Price")

t.build_rows(@order_positions) do |row, p| # block can be omitted
row[:doubled_price] = p.price*2
row[:doubled_price] = p.price * 2
end


# Grouping

grouped_table = t.group_by(:ordered, {
:amount => DataTable::Aggregators::SUM,
:doubled_price => DataTable::Aggregators::SUM
}, lambda {|x| x.year.to_s+"-"+x.month.to_s})
}, lambda { |x| "#{x.year}-#{x.month}" })

# puts t.render_csv(:col_sep => ",")
puts grouped_table.render_csv(:col_sep => ",")

end



end
end

0 comments on commit bd7df13

Please sign in to comment.