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