Files
openfoodnetwork/lib/open_food_network/order_grouper.rb

88 lines
2.2 KiB
Ruby

module OpenFoodNetwork
class OrderGrouper
def initialize(rules, column_constructors, report = nil)
@rules = rules
@column_constructors = column_constructors
@report = report
end
def build_tree(items, remaining_rules)
rules = remaining_rules.clone
if rules.any?
rule = rules.delete_at(0) # Remove current rule for subsequent groupings
group_and_sort(rule, rules, items)
else
items
end
end
def group_and_sort(rule, remaining_rules, items)
branch = {}
groups = items.group_by { |item| rule[:group_by].call(item) }
sorted_groups = groups.sort_by { |key, _value| rule[:sort_by].call(key) }
sorted_groups.each do |property, items_by_property|
branch[property] = build_tree(items_by_property, remaining_rules)
next if rule[:summary_columns].nil? || is_leaf_node(branch[property])
branch[property][:summary_row] = {
items: items_by_property,
columns: rule[:summary_columns]
}
end
branch
end
def build_table(groups)
rows = []
if is_leaf_node(groups)
rows << build_row(groups)
else
groups.each do |key, group|
if key == :summary_row
rows << build_summary_row(group[:columns], group[:items])
else
build_table(group).each { |g| rows << g }
end
end
end
rows
end
def table(items)
tree = build_tree(items, @rules)
table = build_table(tree)
table
end
private
def build_cell(column_constructor, items)
if column_constructor.is_a?(Symbol)
@report.__send__(column_constructor, items)
else
column_constructor.call(items)
end
end
def build_row(groups)
@column_constructors.map do |column_constructor|
build_cell(column_constructor, groups)
end
end
def build_summary_row(summary_row_column_constructors, items)
summary_row_column_constructors.map do |summary_row_column_constructor|
build_cell(summary_row_column_constructor, items)
end
end
def is_leaf_node(node)
node.is_a? Array
end
end
end