Class: Ruport::Data::Grouping

Inherits:
Object
  • Object
show all
Includes:
Enumerable, Controller::Hooks
Defined in:
lib/ruport/data/grouping.rb

Overview

Overview

This class implements a grouping data structure for Ruport. A grouping is a collection of groups. It allows you to group the data in a table by one or more columns that you specify.

The data for a grouping is a hash of groups, keyed on each unique data point from the grouping column.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Controller::Hooks

#as, included, #save_as

Constructor Details

#initialize(data = {}, options = {}) ⇒ Grouping

Creates a new Grouping based on the supplied options.

Valid options:

:by

A column name or array of column names that the data will be grouped on.

:order

Determines the iteration and presentation order of a Grouping object. Set to :name to order by Group names. You can also provide a lambda which will be passed Group objects, and use semantics similar to Enumerable#group_by

Examples:

table = [[1,2,3],[4,5,6],[1,1,2]].to_table(%w[a b c])

# unordered 
grouping = Grouping.new(table, :by => "a")

# ordered by group name
grouping = Grouping.new(table, :by => "a", :order => :name)

# ordered by group size
grouping = Grouping.new(table, :by => "a", 
                               :order => lambda { |g| g.size } )


164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/ruport/data/grouping.rb', line 164

def initialize(data={},options={})
  if data.kind_of?(Hash)
    @grouped_by = data[:by]
    @order = data[:order] 
    @data = {}
  else
    @grouped_by = options[:by]    
    @order = options[:order]
    cols = Array(options[:by]).dup
    @data = data.to_group.send(:grouped_data, cols.shift)
    cols.each do |col|
      @data.each do |_name,group|
        group.send(:create_subgroups, col)
      end
    end    
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(id, *args) ⇒ Object

Provides a shortcut for the as() method by converting a call to to_format_name into a call to as(:format_name).



367
368
369
370
# File 'lib/ruport/data/grouping.rb', line 367

def method_missing(id,*args)
  return as($1.to_sym,*args) if id.to_s =~ /^to_(.*)/ 
  super
end

Instance Attribute Details

#dataObject

The grouping’s data



183
184
185
# File 'lib/ruport/data/grouping.rb', line 183

def data
  @data
end

#grouped_byObject (readonly)

The name of the column used to group the data



186
187
188
# File 'lib/ruport/data/grouping.rb', line 186

def grouped_by
  @grouped_by
end

Class Method Details

.inherited(base) ⇒ Object

:nodoc:



346
347
348
# File 'lib/ruport/data/grouping.rb', line 346

def self.inherited(base) #:nodoc:
  base.renders_as_grouping
end

Instance Method Details

#<<(group) ⇒ Object Also known as: append

Used to add extra data to the Grouping. group should be a Group.

Example:

table = [[1,2,3],[4,5,6]].to_table(%w[a b c])

grouping = Grouping.new(table, :by => "a")

group = Group.new :name => 7,
                  :data => [[8,9]], 
                  :column_names => %w[b c]

grouping << group


245
246
247
248
249
250
# File 'lib/ruport/data/grouping.rb', line 245

def <<(group)        
  if data.has_key? group.name
    raise(ArgumentError, "Group '#{group.name}' exists!") 
  end
  @data.merge!({ group.name => group })
end

#[](name) ⇒ Object

Allows Hash-like indexing of the grouping data.

Examples:

my_grouping["foo"]


194
195
196
197
# File 'lib/ruport/data/grouping.rb', line 194

def [](name)
  @data[name] or 
    raise(IndexError,"Group Not Found")
end

#eachObject

Iterates through the Grouping, yielding each group name and Group object



201
202
203
204
205
206
207
208
209
# File 'lib/ruport/data/grouping.rb', line 201

def each 
  if @order.respond_to?(:call) 
    @data.sort_by { |_n,g| @order[g] }.each { |n,g| yield(n,g) }
  elsif @order == :name
    @data.sort_by { |n,_g| n }.each { |name,group| yield(name,group) }
  else
    @data.each { |name,group| yield(name,group) }
  end
end

#initialize_copy(from) ⇒ Object

Create a copy of the Grouping. Groups will be copied as well.

Example:

table = [[1,2,3],[4,5,6]].to_table(%w[a b c])
one = Ruport::Data::Grouping.new(a, :by => "a")

two = one.dup


359
360
361
362
# File 'lib/ruport/data/grouping.rb', line 359

def initialize_copy(from)  #:nodoc:
  @grouped_by = from.grouped_by
  @data = from.data.inject({}) { |h,d| h.merge!({ d[0] => d[1].dup }) }
end

#sigma(column = nil) ⇒ Object Also known as: sum

Calculates sums. If a column name or index is given, it will try to convert each element of that column to an integer or float and add them together. The sum is calculated across all groups in the grouping.

If a block is given, it yields each Record in each Group so that you can do your own calculation.

Example:

table = [[1,2,3],[3,4,5],[5,6,7]].to_table(%w[col1 col2 col3])
grouping = Grouping(table, :by => "col1")
grouping.sigma("col2") #=> 12
grouping.sigma(0)      #=> 12
grouping.sigma { |r| r.col2 + r.col3 } #=> 27
grouping.sigma { |r| r.col2 + 1 } #=> 15


329
330
331
332
333
334
335
336
337
338
339
# File 'lib/ruport/data/grouping.rb', line 329

def sigma(column=nil)
  inject(0) do |s, (_group_name, group)|
    if column
      s + group.sigma(column)
    else
      s + group.sigma do |r|
        yield(r)
      end
    end
  end
end

#sort_grouping_by(type = nil, &block) ⇒ Object

Returns a new grouping with the specified sort order. You can sort by Group name or an arbitrary block

by_name = grouping.sort_grouping_by(:name) 
by_size = grouping.sort_grouping_by { |g| g.size }


217
218
219
220
221
# File 'lib/ruport/data/grouping.rb', line 217

def sort_grouping_by(type=nil,&block)
  a = Grouping.new(:by => @grouped_by, :order => type || block)
  each { |_n,g| a << g }
  return a
end

#sort_grouping_by!(type = nil, &block) ⇒ Object

Applies the specified sort order to an existing Grouping object.

grouping.sort_grouping_by!(:name)
grouping.sort_grouping_by! { |g| g.size }


227
228
229
# File 'lib/ruport/data/grouping.rb', line 227

def sort_grouping_by!(type=nil,&block)
  @order = type || block
end

#subgrouping(name) ⇒ Object Also known as: /

Provides access to the subgroups of a particular group in the Grouping. Supply the name of a group and it returns a Grouping created from the subgroups of the group.



258
259
260
261
262
# File 'lib/ruport/data/grouping.rb', line 258

def subgrouping(name)
  grouping = dup
  grouping.send(:data=, @data[name].subgroups)
  return grouping
end

#summary(field, procs) ⇒ Object

Useful for creating basic summaries from Grouping objects. Takes a field to summarize on, and then for each group, runs the specified procs and returns the results as a Table.

The following example would show for each date group, the sum for the attributes or methods :opened and :closed and order them by the :order array.

If :order is not specified, you cannot depend on predictable column order.

grouping.summary :date,
  :opened => lambda { |g| g.sigma(:opened) },
  :closed => lambda { |g| g.sigma(:closed) },
  :order => [:date,:opened,:closed]


282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
# File 'lib/ruport/data/grouping.rb', line 282

def summary(field,procs)     
  if procs[:order].kind_of?(Array)
    cols = procs.delete(:order) 
  else 
    cols = procs.keys + [field]   
  end
  Table.new(:column_names => cols) { |t|
    each do |name,group|
      t << procs.inject({field => name}) do |s,r|
        s.merge(r[0] => r[1].call(group))
      end 
    end
    t.data.reorder(cols)     
  }   
end

#to_sObject

Uses Ruport’s built-in text formatter to render this Grouping

Example:

table = [[1,2,3],[4,5,6]].to_table(%w[a b c])

grouping = Grouping.new(table, :by => "a")

puts grouping.to_s


308
309
310
# File 'lib/ruport/data/grouping.rb', line 308

def to_s
  as(:text)
end