Skip to content

Commit

Permalink
feat: Introduce Series and refactor aggregators, formatters and trans…
Browse files Browse the repository at this point in the history
…ponders
  • Loading branch information
jozefvaclavik committed Apr 25, 2024
1 parent 97769a4 commit 21e05a0
Show file tree
Hide file tree
Showing 12 changed files with 125 additions and 106 deletions.
7 changes: 6 additions & 1 deletion lib/trifle/stats.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require 'trifle/stats/mixins/packer'
require 'trifle/stats/series'
require 'trifle/stats/aggregator/max'
require 'trifle/stats/aggregator/min'
require 'trifle/stats/aggregator/sum'
Expand All @@ -12,14 +13,14 @@
require 'trifle/stats/driver/process'
require 'trifle/stats/driver/redis'
require 'trifle/stats/driver/sqlite'
require 'trifle/stats/formatter/category'
require 'trifle/stats/formatter/timeline'
require 'trifle/stats/nocturnal'
require 'trifle/stats/configuration'
require 'trifle/stats/operations/timeseries/classify'
require 'trifle/stats/operations/timeseries/increment'
require 'trifle/stats/operations/timeseries/set'
require 'trifle/stats/operations/timeseries/values'
require 'trifle/stats/transponder'
require 'trifle/stats/transponder/average'
require 'trifle/stats/transponder/standard_deviation'
require 'trifle/stats/version'
Expand Down Expand Up @@ -75,5 +76,9 @@ def self.values(key:, from:, to:, range:, config: nil)
config: config
).perform
end

def self.series(**params)
Trifle::Stats::Series.new(values(**params))
end
end
end
17 changes: 3 additions & 14 deletions lib/trifle/stats/aggregator/max.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,10 @@ module Trifle
module Stats
class Aggregator
class Max
include Trifle::Stats::Mixins::Packer
Trifle::Stats::Series.register_aggregator(:max, self)

attr_reader :series, :path

def initialize(series:, path:)
@series = series
@series[:values] = self.class.normalize(@series[:values])
@path = path
end

def keys
@keys ||= path.split('.')
end

def aggregate
def aggregate(series:, path:)
keys = path.split('.')
result = series[:values].map do |data|
data.dig(*keys).to_f
end
Expand Down
17 changes: 3 additions & 14 deletions lib/trifle/stats/aggregator/min.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,10 @@ module Trifle
module Stats
class Aggregator
class Min
include Trifle::Stats::Mixins::Packer
Trifle::Stats::Series.register_aggregator(:min, self)

attr_reader :series, :path

def initialize(series:, path:)
@series = series
@series[:values] = self.class.normalize(@series[:values])
@path = path
end

def keys
@keys ||= path.split('.')
end

def aggregate
def aggregate(series:, path:)
keys = path.split('.')
result = series[:values].map do |data|
data.dig(*keys).to_f
end
Expand Down
17 changes: 3 additions & 14 deletions lib/trifle/stats/aggregator/sum.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,10 @@ module Trifle
module Stats
class Aggregator
class Sum
include Trifle::Stats::Mixins::Packer
Trifle::Stats::Series.register_aggregator(:sum, self)

attr_reader :series, :path

def initialize(series:, path:)
@series = series
@series[:values] = self.class.normalize(@series[:values])
@path = path
end

def keys
@keys ||= path.split('.')
end

def aggregate
def aggregate(series:, path:)
keys = path.split('.')
result = series[:values].map do |data|
data.dig(*keys).to_f
end
Expand Down
2 changes: 1 addition & 1 deletion lib/trifle/stats/driver/redis.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class Redis
include Mixins::Packer
attr_accessor :client, :prefix, :separator

def initialize(client = ::Redis.current, prefix: 'trfl')
def initialize(client, prefix: 'trfl')
@client = client
@prefix = prefix
@separator = '::'
Expand Down
21 changes: 21 additions & 0 deletions lib/trifle/stats/formatter/category.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true

module Trifle
module Stats
class Formatter
class Category
Trifle::Stats::Series.register_formatter(:category, self)

def format(series:, path:)
keys = path.split('.')
series[:at].each_with_object(Hash.new(0)).with_index do |(_at, map), i|
series[:values][i].dig(*keys).each do |key, value|
k, v = block_given? ? yield(key, value) : [key.to_s, value.to_f]
map[k] += v
end
end
end
end
end
end
end
11 changes: 2 additions & 9 deletions lib/trifle/stats/formatter/timeline.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,9 @@ module Trifle
module Stats
class Formatter
class Timeline
include Trifle::Stats::Mixins::Packer
Trifle::Stats::Series.register_formatter(:timeline, self)

attr_reader :series

def initialize(series:)
@series = series
@series[:values] = self.class.normalize(@series[:values])
end

def format(path:)
def format(series:, path:)
keys = path.split('.')
series[:at].map.with_index do |at, i|
value = series[:values][i].dig(*keys)
Expand Down
4 changes: 3 additions & 1 deletion lib/trifle/stats/mixins/packer.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# frozen_string_literal: true

require 'bigdecimal'

module Trifle
module Stats
module Mixins
Expand Down Expand Up @@ -56,7 +58,7 @@ def normalize(object)
when Array
object.map { |v| normalize(v) }
else
object
BigDecimal(object)
end
end
end
Expand Down
64 changes: 64 additions & 0 deletions lib/trifle/stats/series.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# frozen_string_literal: true

module Trifle
module Stats
class Series
include Trifle::Stats::Mixins::Packer

attr_accessor :series

def initialize(series)
@series = series
@series[:values] = self.class.normalize(@series[:values])
end

class Aggregator
def initialize(series)
@series = series
end
end

def aggregate
@aggregate ||= Aggregator.new(self)
end

def self.register_aggregator(name, klass)
Aggregator.define_method(name) do |params|
klass.new.aggregate(series: @series.series, **params)
end
end

class Formatter
def initialize(series)
@series = series
end
end

def format
@format ||= Formatter.new(self)
end

def self.register_formatter(name, klass)
Formatter.define_method(name) do |params, &block|
klass.new.format(series: @series.series, **params, &block)
end
end

class Transponder
def initialize(series)
@series = series
end
end

def transpond
@transpond ||= Transponder.new(self)
end

def self.register_transponder(name, klass)
Transponder.define_method(name) do |params|
@series.series = klass.new.transpond(series: @series.series, **params)
end
end
end
end
end
25 changes: 0 additions & 25 deletions lib/trifle/stats/transponder.rb

This file was deleted.

18 changes: 8 additions & 10 deletions lib/trifle/stats/transponder/average.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,17 @@ module Stats
class Transponder
class Average
include Trifle::Stats::Mixins::Packer
Trifle::Stats::Series.register_transponder(:average, self)

attr_reader :sum, :count

def initialize(sum: 'sum', count: 'count')
@sum = sum
@count = count
end

def transpond(series:, path:)
keys = path.split('.')
def transpond(series:, path:, sum: 'sum', count: 'count') # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
keys = path.to_s.split('.')
key = [path, 'average'].compact.join('.')
series[:values] = series[:values].map do |data|
dsum = data.dig(*keys, sum) || BigDecimal(0)
dcount = data.dig(*keys, count) || BigDecimal(0)
dres = (dsum / dcount)
signal = {
"#{path}.average" => data.dig(*keys, sum) / data.dig(*keys, count)
key => dres.nan? ? BigDecimal(0) : dres
}
self.class.deep_merge(data, self.class.unpack(hash: signal))
end
Expand Down
28 changes: 11 additions & 17 deletions lib/trifle/stats/transponder/standard_deviation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,20 @@ module Stats
class Transponder
class StandardDeviation
include Trifle::Stats::Mixins::Packer
Trifle::Stats::Series.register_transponder(:standard_deviation, self)

attr_reader :sum, :count, :square

def initialize(sum: 'sum', count: 'count', square: 'square')
@sum = sum
@count = count
@square = square
end

def transpond(series:, path:) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
keys = path.split('.')

def transpond(series:, path:, sum: 'sum', count: 'count', square: 'square') # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
keys = path.to_s.split('.')
key = [path, 'sd'].compact.join('.')
series[:values] = series[:values].map do |data|
dcount = data.dig(*keys, count)
dsquare = data.dig(*keys, square)
dsum = data.dig(*keys, sum)
dcount = data.dig(*keys, count) || BigDecimal(0)
dsquare = data.dig(*keys, square) || BigDecimal(0)
dsum = data.dig(*keys, sum) || BigDecimal(0)
dres = Math.sqrt(
(dcount * dsquare - dsum * dsum) / (dcount * (dcount - 1)) # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands
)
signal = {
"#{path}.sd" => Math.sqrt(
(dcount * dsquare - dsum * dsum) / (dcount * (dcount - 1)) # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands
)
key => dres.nan? ? BigDecimal(0) : dres
}
self.class.deep_merge(data, self.class.unpack(hash: signal))
end
Expand Down

0 comments on commit 21e05a0

Please sign in to comment.