Class: AllocationStats::AllocationsProxy

Inherits:
Object
  • Object
show all
Defined in:
lib/allocation_stats/allocations_proxy.rb

Overview

AllocationsProxy acts as a proxy for an array of Allocation objects. The idea behind this class is merely to provide some domain-specific methods for transforming (filtering, sorting, and grouping) allocation information. This class uses the Command pattern heavily, in order to build and maintain the list of transforms it will ultimately perform, before retrieving the transformed collection of Allocations.

Chaining

Use of the Command pattern and Procs allows for transform-chaining in any order. Apply methods such as #from and #group_by to build the internal list of transforms. The transforms will not be applied to the collection of Allocations until a call to #to_a (#all) resolves them.

Filtering Transforms

Methods that filter the collection of Allocations will add a transform to an Array, @wheres. When the result set is finally retrieved, each where is applied serially, so that @wheres represents a logical conjunction ("and") of of filtering transforms. Presently there is no way to "or" filtering transforms together with a logical disjunction.

Mapping Transforms

Grouping Transform

Only one method will allow a grouping transform: #group_by. Only one grouping transform is allowed; subsequent calls to #group_by will only replace the previous grouping transform.

Constant Summary collapse

DEFAULT_COLUMNS =

default columns for the tabular output

[:sourcefile, :sourceline, :class_path, :method_id, :memsize, :class]
NUMERIC_COLUMNS =

columns that should be right-aligned for the tabular output

[:sourceline, :memsize]

Instance Method Summary collapse

Constructor Details

#initialize(allocations, alias_paths: false) ⇒ AllocationsProxy

Instantiate an AllocationStats::AllocationsProxy with an array of Allocations. AllocationProxy's view of pwd is set at instantiation.

Parameters:

  • allocations (Array<Allocation>)

    array of Allocation objects



44
45
46
47
48
49
50
51
# File 'lib/allocation_stats/allocations_proxy.rb', line 44

def initialize(allocations, alias_paths: false)
  @allocations = allocations
  @pwd = Dir.pwd
  @wheres = []
  @group_by = nil
  @mappers  = []
  @alias_paths = alias_paths
end

Instance Method Details

#alias_paths(value = nil) ⇒ Object



72
73
74
75
76
77
78
79
80
# File 'lib/allocation_stats/allocations_proxy.rb', line 72

def alias_paths(value = nil)
  # reader
  return @alias_paths if value.nil?

  # writer
  @alias_paths = value

  return self
end

#bytesObject

Map to bytes via #memsize. This is done in one of two ways:

  • If the current result set is an Array, then this transform just maps each Allocation to its #memsize.
  • If the current result set is a Hash (meaning it has been grouped), then this transform maps each value in the Hash (which is an Array of Allocations) to the sum of the Allocation #memsizes within.


188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/allocation_stats/allocations_proxy.rb', line 188

def bytes
  @mappers << Proc.new do |allocations|
    if allocations.is_a? Array
      allocations.map(&:memsize)
    elsif allocations.is_a? Hash
      bytes_h = {}
      allocations.each do |key, allocations|
        bytes_h[key] = allocations.inject(0) { |sum, allocation| sum + allocation.memsize }
      end
      bytes_h
    end
  end

  self
end

#from(pattern) ⇒ Object

Select allocations for which the sourcefile includes pattern.

#from can be called multiple times, adding to @wheres. See documentation for AllocationStats::AllocationsProxy for more information about chaining.

Parameters:



100
101
102
103
104
105
106
# File 'lib/allocation_stats/allocations_proxy.rb', line 100

def from(pattern)
  @wheres << Proc.new do |allocations|
    allocations.select { |allocation| allocation.sourcefile[pattern] }
  end

  self
end

#from_pwdObject

Select allocations for which the sourcefile includes the present working directory.

#from_pwd can be called multiple times, adding to @wheres. See documentation for AllocationStats::AllocationsProxy for more information about chaining.



129
130
131
132
133
134
135
# File 'lib/allocation_stats/allocations_proxy.rb', line 129

def from_pwd
  @wheres << Proc.new do |allocations|
    allocations.select { |allocation| allocation.sourcefile[@pwd] }
  end

  self
end

#group_by(*args) ⇒ Object



137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/allocation_stats/allocations_proxy.rb', line 137

def group_by(*args)
  @group_keys = args

  @group_by = Proc.new do |allocations|
    getters = attribute_getters(@group_keys)

    allocations.group_by do |allocation|
      getters.map { |getter| getter.call(allocation) }
    end
  end

  self
end

#not_from(pattern) ⇒ Object

Select allocations for which the sourcefile does not include pattern.

#not_from can be called multiple times, adding to @wheres. See documentation for AllocationStats::AllocationsProxy for more information about chaining.

Parameters:



116
117
118
119
120
121
122
# File 'lib/allocation_stats/allocations_proxy.rb', line 116

def not_from(pattern)
  @wheres << Proc.new do |allocations|
    allocations.reject { |allocation| allocation.sourcefile[pattern] }
  end

  self
end

#sort_by_sizeObject Also known as: sort_by_count



82
83
84
85
86
87
88
89
# File 'lib/allocation_stats/allocations_proxy.rb', line 82

def sort_by_size
  @mappers << Proc.new do |allocations|
    allocations.sort_by { |key, value| -value.size }
               .inject({}) { |hash, pair| hash[pair[0]] = pair[1]; hash }
  end

  self
end

#to_aObject Also known as: all



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/allocation_stats/allocations_proxy.rb', line 53

def to_a
  results = @allocations

  @wheres.each do |where|
    results = where.call(results)
  end

  # First apply group_by
  results = @group_by.call(results) if @group_by

  # Apply each mapper
  @mappers.each do |mapper|
    results = mapper.call(results)
  end

  results
end

#to_jsonObject



229
230
231
# File 'lib/allocation_stats/allocations_proxy.rb', line 229

def to_json
  to_a.to_json
end

#to_text(columns: DEFAULT_COLUMNS) ⇒ String

Resolve the AllocationsProxy (by calling #to_a) and return tabular information about the Allocations as a String.

Parameters:

  • columns (Array<Symbol>) (defaults to: DEFAULT_COLUMNS)

    a list of columns to print out

Returns:

  • (String)

    information about the Allocations, in a tabular format



216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/allocation_stats/allocations_proxy.rb', line 216

def to_text(columns: DEFAULT_COLUMNS)
  resolved = to_a

  # if resolved is an Array of Allocations
  if resolved.is_a?(Array) && resolved.first.is_a?(Allocation)
    to_text_from_plain(resolved, columns: columns)

  # if resolved is a Hash (was grouped)
  elsif resolved.is_a?(Hash)
    to_text_from_groups(resolved)
  end
end

#where(hash) ⇒ Object



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/allocation_stats/allocations_proxy.rb', line 151

def where(hash)
  @wheres << Proc.new do |allocations|
    conditions = hash.inject({}) do |h, pair|
      faux, value = *pair
      getter = attribute_getters([faux]).first
      h.merge(getter => value)
    end

    allocations.select do |allocation|
      conditions.all? { |getter, value| getter.call(allocation) == value }
    end
  end

  self
end