Class: Repor::Report

Inherits:
Object
  • Object
show all
Defined in:
lib/repor/report.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(params = {}) ⇒ Report

Returns a new instance of Report.



7
8
9
10
11
# File 'lib/repor/report.rb', line 7

def initialize(params = {})
  @params = params.deep_symbolize_keys.deep_dup
  deep_strip_blanks(@params) unless @params[:strip_blanks] == false
  validate_params!
end

Instance Attribute Details

#paramsObject (readonly)

Returns the value of attribute params.



5
6
7
# File 'lib/repor/report.rb', line 5

def params
  @params
end

Class Method Details

.aggregator(name, aggregator_class, opts = {}) ⇒ Object



110
111
112
# File 'lib/repor/report.rb', line 110

def aggregator(name, aggregator_class, opts = {})
  aggregators[name.to_sym] = { axis_class: aggregator_class, opts: opts }
end

.aggregatorsObject



106
107
108
# File 'lib/repor/report.rb', line 106

def aggregators
  @aggregators ||= {}
end

.autoreport_association_name_columns(reflection) ⇒ Object

override this to change which columns of the association are used to auto-label it



182
183
184
# File 'lib/repor/report.rb', line 182

def autoreport_association_name_columns(reflection)
  %w(name email title)
end

.autoreport_column(column) ⇒ Object

can override this method to skip or change certain column declarations



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/repor/report.rb', line 159

def autoreport_column(column)
  return if column.name == 'id'
  belongs_to_ref = klass.reflections.find { |_, a| a.foreign_key == column.name }
  if belongs_to_ref
    name, ref = belongs_to_ref
    name_col = (ref.klass.column_names & autoreport_association_name_columns(ref)).first
    if name_col
      name_expr = "#{ref.klass.table_name}.#{name_col}"
      category_dimension name, expression: name_expr, relation: ->(r) { r.joins(name) }
    else
      category_dimension column.name
    end
  elsif column.cast_type.type == :datetime
    time_dimension column.name
  elsif column.cast_type.number?
    number_dimension column.name
  else
    category_dimension column.name
  end
end

.autoreport_on(class_or_name) ⇒ Object

autoreporting will automatically define dimensions based on columns



152
153
154
155
156
# File 'lib/repor/report.rb', line 152

def autoreport_on(class_or_name)
  report_on class_or_name
  klass.columns.each(&method(:autoreport_column))
  count_aggregator :count if aggregators.blank?
end

.default_classObject



130
131
132
# File 'lib/repor/report.rb', line 130

def default_class
  self.name.demodulize.sub(/Report$/, '').constantize
end

.dimension(name, dimension_class, opts = {}) ⇒ Object



102
103
104
# File 'lib/repor/report.rb', line 102

def dimension(name, dimension_class, opts = {})
  dimensions[name.to_sym] = { axis_class: dimension_class, opts: opts }
end

.dimensionsObject



98
99
100
# File 'lib/repor/report.rb', line 98

def dimensions
  @dimensions ||= {}
end

.inherited(subclass) ⇒ Object

ensure subclasses gain any aggregators or dimensions defined on their parents



145
146
147
148
149
# File 'lib/repor/report.rb', line 145

def inherited(subclass)
  instance_values.each do |ivar, ival|
    subclass.instance_variable_set(:"@#{ivar}", ival.dup)
  end
end

.klassObject



134
135
136
137
138
# File 'lib/repor/report.rb', line 134

def klass
  @klass ||= default_class
rescue NameError
  raise NameError, "must specify a class to report on, e.g. `report_on Post`"
end

.report_on(class_or_name) ⇒ Object



140
141
142
# File 'lib/repor/report.rb', line 140

def report_on(class_or_name)
  @klass = class_or_name.to_s.constantize
end

Instance Method Details

#aggregatorObject



25
26
27
# File 'lib/repor/report.rb', line 25

def aggregator
  @aggregator ||= aggregators[aggregator_name]
end

#aggregator_nameObject



21
22
23
# File 'lib/repor/report.rb', line 21

def aggregator_name
  params.fetch(:aggregator, default_aggregator_name).to_sym
end

#aggregatorsObject



17
18
19
# File 'lib/repor/report.rb', line 17

def aggregators
  @aggregators ||= build_axes(self.class.aggregators)
end

#base_relationObject



47
48
49
# File 'lib/repor/report.rb', line 47

def base_relation
  params.fetch(:relation, klass.all)
end

#dataObject



93
94
95
# File 'lib/repor/report.rb', line 93

def data
  nested_data
end

#dimensionsObject



13
14
15
# File 'lib/repor/report.rb', line 13

def dimensions
  @dimensions ||= build_axes(self.class.dimensions)
end

#filtersObject



39
40
41
# File 'lib/repor/report.rb', line 39

def filters
  @filters ||= dimensions.values.select(&:filtering?)
end

#flat_dataObject

flat hash of { [x1, x2, x3] => y }



83
84
85
# File 'lib/repor/report.rb', line 83

def flat_data
  @flat_data ||= Hash[group_values.map { |x| [x, raw_data[x]] }]
end

#group_valuesObject



77
78
79
# File 'lib/repor/report.rb', line 77

def group_values
  @group_values ||= all_combinations_of(groupers.map(&:group_values))
end

#grouper_namesObject



29
30
31
32
33
# File 'lib/repor/report.rb', line 29

def grouper_names
  names = params.fetch(:groupers, default_grouper_names)
  names = names.is_a?(Hash) ? names.values : Array.wrap(names)
  names.map(&:to_sym)
end

#groupersObject



35
36
37
# File 'lib/repor/report.rb', line 35

def groupers
  @groupers ||= dimensions.values_at(*grouper_names)
end

#groupsObject



67
68
69
70
71
# File 'lib/repor/report.rb', line 67

def groups
  @groups ||= groupers.reduce(records) do |relation, dimension|
    dimension.group(relation)
  end
end

#nested_dataObject

nested array of

{ key: x3, values: [{ key: x2, values: [{ key: x1, value: y }

}] }]



89
90
91
# File 'lib/repor/report.rb', line 89

def nested_data
  @nested_data ||= nest_data
end

#raw_dataObject



73
74
75
# File 'lib/repor/report.rb', line 73

def raw_data
  @raw_data ||= aggregator.aggregate(groups)
end

#recordsObject



61
62
63
64
65
# File 'lib/repor/report.rb', line 61

def records
  @records ||= filters.reduce(relation) do |relation, dimension|
    dimension.filter(relation)
  end
end

#relationObject



55
56
57
58
59
# File 'lib/repor/report.rb', line 55

def relation
  @relation ||= relators.reduce(base_relation) do |relation, dimension|
    dimension.relate(relation)
  end
end

#relatorsObject



43
44
45
# File 'lib/repor/report.rb', line 43

def relators
  filters | groupers
end

#table_nameObject



51
52
53
# File 'lib/repor/report.rb', line 51

def table_name
  klass.table_name
end