lib/sum_sum.rb in sum_sum-0.0.4 vs lib/sum_sum.rb in sum_sum-0.0.5

- old
+ new

@@ -1,80 +1,126 @@ +# = SumSum +# +# SumSum allows you to generate simple reports on the count of values in hashes. class SumSum < Hash + # @overload initialize(*keys, options = {}) + # @param [Symbol,String] *args the keys to anaylze on hashes + # @param [Hash] options are only used internaly + # + # @example Create a SumSum to analyze hashes with attributes :gender, :age and :name + # SumSum.new(:gender, :age, :name) def initialize(*args) - @parent = args.pop if args[-1].is_a?(self.class) - @name = args.shift - @args = args.compact.dup - @count = 0 + options = args[-1].is_a?(Hash) ? args.pop : {} + @key, @parent, @level = options[:key], options[:parent], (options[:level] || 0) + @kind_of_children, @args, @count = args[level], args, 0 super() end - - attr_reader :name, :args, :count, :parent - - def add(hash, increase_by=1) - key = hash[name] - @count = @count + increase_by + + attr_reader :kind_of_children, :key, :args, :count, :parent, :level + + # Add a new hash to analyze. + # + # @param [Hash,#[]] hash the data to add to the SumSum instance + # @param [Integer] increase_count_by amount to add to count + # @return [SumSum] Returns itself + # + # @example Add some data + # sum_sum.add(:gender => "W", :age => 23, :name => "Nina") + # sum_sum.add(:gender => "M", :age => 77, :name => "Carl") + # sum_sum.add(:gender => "W", :age => 33, :name => "Nora") + def add(hash, increase_count_by=1) + @count = @count + increase_count_by unless bottom? - self[key] ||= SumSum.new(*args, self) - self[key].add(hash, increase_by) + key = hash[kind_of_children] + self[key] ||= SumSum.new(*args, :parent => self, :key => key, :level => level + 1) + self[key].add(hash, increase_count_by) end self end - + + # Returns share compared to parent + # + # @return [Float] Returns the share between 0.0 and 1.0 + # + # @example Get share of all (returns alway 1.0) + # sum_sum.share + # => 1.0 + # @example Get share of all women compared to all entries (two out of three) + # sum_sum["W"].share + # => 0.75 + # @example Get share of all women with age 23 compared to all women entries (one out of two) + # sum_sum["W"][23].share + # => 0.5 def share root? ? 1.0 : count/parent.count.to_f end - + + # Returns share compared to all entries + # + # @return [Float] Returns the share between 0.0 and 1.0 + # + # @example Get share of all (returns alway 1.0) + # sum_sum.total_share + # => 1.0 + # @example Get share of all women compared to all entries (two out of three) + # sum_sum["W"].total_share + # => 0.75 + # @example Get share of all women with age 23 compared to all entries (one out of three) + # sum_sum["W"][23].total_share + # => 0.3333333 + def total_share + count/root.count.to_f + end + def sort! return self if bottom? values.each(&:sort!) to_a.sort_by{|it| it[1].count}.reverse.tap do |array| - clear - array.each{|k, v| self[k] = v } + clear && array.each{|k, v| self[k] = v } end self end - + def root? - parent.nil? + !parent end - + def bottom? - name.nil? + !kind_of_children end - + + def root + root? ? self : parent.root + end + def inspect - bottom? ? "#{count}" : "{#{name}:#{count} #{super.gsub(/^\{|\}$/, "")}}" + bottom? ? "#{count}" : "{#{kind_of_children}:#{count} #{super.gsub(/^\{|\}$/, "")}}" end - + def pretty_print(pp) return pp.text(" #{count}") if bottom? super end - + def dump return count if bottom? hash = {} each{ |k, v| hash[k] = v.dump } - root? ? [all_args, hash] : hash + root? ? [args, hash] : hash end - + def self.load(data) new(*data[0]).tap do |sum_sum| sum_sum.add_from_dump(data[1]) end end - - def add_from_dump(data, hash={}, level=0) - data.each do |key, value| - hash[all_args[level]] = key - value.is_a?(Hash) ? - add_from_dump(value, hash, level + 1) : - add(hash, value) + + def add_from_dump(data, hash={}, on_level=0) + data.each do |k, v| + hash[args[on_level]] = k + v.is_a?(Hash) ? + add_from_dump(v, hash, on_level + 1) : + add(hash, v) end end - - private - - def all_args - [name] + args - end + end