<commit_before># Reportage - the Mostfit Reporting Library

class BucketResult < Hash


  # The results from a Bucket#columns is stored as a BucketResult so that we can
  # print fancy tables and stuff

  def hash_to_string(title = "", separator = "|", width = 10, padding = 4)
    titles = [title] + self.values.first.keys
    puts titles.map{|t| t.to_s[0..width - 1].rjust(width - padding/2).ljust(width)}.join(separator)
    keys = self.keys.first
    numeric_keys = true if Float(self.keys.first) rescue false
    if numeric_keys
      h = self.map{|k,v| [k.to_i,v]}.to_hash
    else
      h = self
    end
    oink = h.keys.sort.map{|k| v = h[k];[k] + v.map{|_k,_v| (_v.is_a? Numeric) ? _v.round(2) : _v}}
    oink.map{|a| a.map{|s| s.to_s.rjust(width - padding/2).ljust(width)}}.map{|a| a.join(separator)}.join("\n")
  end

  def to_ascii_table(title = "", width = 10, padding = 4)
    hash_to_string(title, "|", width, padding)
  end
  
  def to_csv(title = "", width = 10, padding = 4)
    hash_to_string(title, ",", width, padding)
  end
end #BucketResult

class Bucket < Hash
  attr_accessor :_balances, :date, :date_from, :date_to

  def initialize(dates = {}, *args, &blk)
    set_dates(dates)
    @_balances = {}
    super(*args, &blk)
  end

  def set_dates(dates = {})
    dates.each{|k,v| instance_variable_set("@#{k.to_s}",v)}
  end

  # for now, lets bucket only by properties defined on the model
  def group_by(group_by)
    result = self.class.new

    each do |key, value|
      result[key] = value.group_by(group_by)
    end

    result
  end

  def columns(cols)
    rv = BucketResult.new
    self.keys.each{|b| rv[b.to_s] = {}}
    cols.map do |function|
      ds = []
      case method(function).arity
      when 0
        ds = []
      when 1
        ds = [@date]
      when 2
        ds = [@date_from, @date_to]
      end
      self.send(function, *ds).each do |b,v| 
        rv[b.to_s] = rv[b.to_s].merge(function => v)
      end
    end
    rv
  end
end #Bucket

# Conjure a bucket class on demand ;). So, we don't have to define empty bucket<commit_msg>reportage: another pass at bucket chaining<commit_after># Reportage - the Mostfit Reporting Library

class BucketResult < Hash


  # The results from a Bucket#columns is stored as a BucketResult so that we can
  # print fancy tables and stuff

  def hash_to_string(title = "", separator = "|", width = 10, padding = 4)
    titles = [title] + self.values.first.keys
    puts titles.map{|t| t.to_s[0..width - 1].rjust(width - padding/2).ljust(width)}.join(separator)
    keys = self.keys.first
    numeric_keys = true if Float(self.keys.first) rescue false
    if numeric_keys
      h = self.map{|k,v| [k.to_i,v]}.to_hash
    else
      h = self
    end
    oink = h.keys.sort.map{|k| v = h[k];[k] + v.map{|_k,_v| (_v.is_a? Numeric) ? _v.round(2) : _v}}
    oink.map{|a| a.map{|s| s.to_s.rjust(width - padding/2).ljust(width)}}.map{|a| a.join(separator)}.join("\n")
  end

  def to_ascii_table(title = "", width = 10, padding = 4)
    hash_to_string(title, "|", width, padding)
  end
  
  def to_csv(title = "", width = 10, padding = 4)
    hash_to_string(title, ",", width, padding)
  end
end #BucketResult

class Bucket < Hash
  attr_accessor :_balances, :date, :date_from, :date_to

  def initialize(dates = {}, *args, &blk)
    set_dates(dates)
    @_balances = {}
    super(*args, &blk)
  end

  def set_dates(dates = {})
    dates.each{|k,v| instance_variable_set("@#{k.to_s}",v)}
  end

  def group_by(group_by = nil, &blk)
    result = self.class.new

    each do |key, value|
      result[key] = value.group_by(group_by, &blk)
    end

    result
  end

  def columns(cols)
    rv = BucketResult.new
    self.keys.each{|b| rv[b.to_s] = {}}
    cols.map do |function|
      ds = []
      case method(function).arity
      when 0
        ds = []
      when 1
        ds = [@date]
      when 2
        ds = [@date_from, @date_to]
      end
      self.send(function, *ds).each do |b,v| 
        rv[b.to_s] = rv[b.to_s].merge(function => v)
      end
    end
    rv
  end
end #Bucket

# Conjure a bucket class on demand ;). So, we don't have to define empty bucket
{'fraction_non_alphanumeric': 0.14650602409638555, 'fraction_numerical': 0.00819277108433735, 'mean_word_length': 2.766787658802178, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2079917', 'n_tokens_mistral': 1612, 'n_tokens_neox': 1531, 'n_words': 386}