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' require 'fastercsv'


class DataTable class DataTable

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


INFINITY = 1.0/0 INFINITY = 1.0 / 0


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


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

end end


class Column class Column
attr_accessor :key
attr_accessor :header attr_accessor :key, :header, :transformer
attr_accessor :transformer


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

end end


class Row class Row

attr_accessor :cells attr_accessor :cells


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


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


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

end end

attr_accessor :columns
attr_accessor :rows attr_accessor :rows, :columns


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


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


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


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


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


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


# copy implicitly selected colums from original data table # 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| aggregators.each_key do |key|
result.add_column(key, @columns[key].header) result.add_column(key, columns[key].header)
end end


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


csv << headers csv << headers


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


end end
end end
end



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


class TestDataTable < Test::Unit::TestCase class TestDataTable < Test::Unit::TestCase

context "A DataTable instance" do context "A DataTable instance" do
setup 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, 200.0 ),
OrderPosition.new("DTJA6181", "R2DX", "BB", Date.new(2009, 10, 4), 1, 20.0 ) OrderPosition.new("DTJA6181", "R2DX", "BB", Date.new(2009, 10, 4), 1, 20.0 )
] ]

end end


should "work properly" do should "work properly" do


t = DataTable.new t = DataTable.new


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

t.build_rows(@order_positions) do |row, p| # block can be omitted 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 end


# Grouping

grouped_table = t.group_by(:ordered, { grouped_table = t.group_by(:ordered, {
:amount => DataTable::Aggregators::SUM, :amount => DataTable::Aggregators::SUM,
:doubled_price => 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 t.render_csv(:col_sep => ",")
puts grouped_table.render_csv(:col_sep => ",") puts grouped_table.render_csv(:col_sep => ",")

end end




end end
end end

0 comments on commit bd7df13

Please sign in to comment.