1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-08-04 21:15:19 +02:00

Reindent TimeSeries classes

This commit is contained in:
Jose Farias 2024-04-18 18:03:52 -06:00
parent f5f624881f
commit e175aa9b49
2 changed files with 91 additions and 92 deletions

View file

@ -1,83 +1,82 @@
class TimeSeries class TimeSeries
attr_reader :type attr_reader :type
def self.from_collection(collection, value_method, options = {}) def self.from_collection(collection, value_method, options = {})
data = collection.map do |obj| data = collection.map do |obj|
{ date: obj.date, value: obj.public_send(value_method), original: obj } { date: obj.date, value: obj.public_send(value_method), original: obj }
end
new(data, options)
end end
new(data, options)
end
def initialize(data, options = {}) def initialize(data, options = {})
@type = options[:type] || :normal @type = options[:type] || :normal
initialize_series_data(data) initialize_series_data(data)
end end
def values def values
@values ||= add_trends_to_series @values ||= add_trends_to_series
end end
def first def first
values.first values.first
end end
def last def last
values.last values.last
end end
def on(date) def on(date)
values.find { |v| v.date == date } values.find { |v| v.date == date }
end end
def trend def trend
TimeSeries::Trend.new( TimeSeries::Trend.new(
current: last&.value, current: last&.value,
previous: first&.value, previous: first&.value,
type: @type type: @type
) )
end end
# Data shape that frontend expects for D3 charts # Data shape that frontend expects for D3 charts
def to_json(*_args) def to_json(*_args)
{
values: values.map do |v|
{ {
values: values.map do |v| date: v.date,
{ value: JSON.parse(v.value.to_json),
date: v.date, trend: {
value: JSON.parse(v.value.to_json), type: v.trend.type,
trend: { direction: v.trend.direction,
type: v.trend.type, value: JSON.parse(v.trend.value.to_json),
direction: v.trend.direction, percent: v.trend.percent
value: JSON.parse(v.trend.value.to_json), }
percent: v.trend.percent }
} end,
} trend: {
end, type: @type,
trend: { direction: trend.direction,
type: @type, value: JSON.parse(trend.value.to_json),
direction: trend.direction, percent: trend.percent
value: JSON.parse(trend.value.to_json), },
percent: trend.percent type: @type
}, }.to_json
type: @type end
}.to_json
private
def initialize_series_data(data)
@series_data = data.nil? || data.empty? ? [] : data.map { |d| TimeSeries::Value.new(d) }.sort_by(&:date)
end end
private def add_trends_to_series
def initialize_series_data(data) [ nil, *@series_data ].each_cons(2).map do |previous, current|
@series_data = data.nil? || data.empty? ? [] : data.map { |d| TimeSeries::Value.new(d) }.sort_by(&:date) unless current.trend
end current.trend = TimeSeries::Trend.new(
current: current.value,
def add_trends_to_series previous: previous&.value,
[ nil, *@series_data ].each_cons(2).map do |previous, current| type: @type
unless current.trend )
current.trend = TimeSeries::Trend.new(
current: current.value,
previous: previous&.value,
type: @type
)
end
current
end
end end
current
end
end
end end

View file

@ -1,32 +1,32 @@
class TimeSeries::Value class TimeSeries::Value
include Comparable include Comparable
attr_accessor :trend attr_accessor :trend
attr_reader :value, :date, :original attr_reader :value, :date, :original
def initialize(obj) def initialize(obj)
@original = obj.fetch(:original, obj) @original = obj.fetch(:original, obj)
if obj.is_a?(Hash) if obj.is_a?(Hash)
@date = obj[:date] @date = obj[:date]
@value = obj[:value] @value = obj[:value]
else else
@date = obj.date @date = obj.date
@value = obj.value @value = obj.value
end
validate_input
end end
def <=>(other) validate_input
result = date <=> other.date end
result = value <=> other.value if result == 0
result
end
private def <=>(other)
def validate_input result = date <=> other.date
raise ArgumentError, "Date is required" unless @date.is_a?(Date) result = value <=> other.value if result == 0
raise ArgumentError, "Money or Numeric value is required" unless @value.is_a?(Money) || @value.is_a?(Numeric) result
end end
private
def validate_input
raise ArgumentError, "Date is required" unless @date.is_a?(Date)
raise ArgumentError, "Money or Numeric value is required" unless @value.is_a?(Money) || @value.is_a?(Numeric)
end
end end