Extract class to manage GeozoneStats

Even if this class looks very simple now, we're trying a few things
related to these stats. Having a class for it makes future changes
easier and, if there weren't any future changes, at least it makes
current experiments easier.

Note we keep the method `participants_by_geozone` to return a hash
because we're caching the stats and storing GeozoneStats objects would
need a lot more memory and we would get an error.
This commit is contained in:
Javi Martín
2019-03-19 13:04:38 +01:00
parent 558070d530
commit 383909e16c
4 changed files with 85 additions and 10 deletions

View File

@@ -69,19 +69,21 @@ module Statisticable
end end
def participants_by_geozone def participants_by_geozone
geozones.map do |geozone| geozone_stats.map do |stats|
count = participants.where(geozone: geozone).count
[ [
geozone.name, stats.name,
{ {
count: count, count: stats.count,
percentage: calculate_percentage(count, total_participants) percentage: stats.percentage
} }
] ]
end.to_h end.to_h
end end
def calculate_percentage(fraction, total)
PercentageCalculator.calculate(fraction, total)
end
private private
def base_stats_methods def base_stats_methods
@@ -124,10 +126,8 @@ module Statisticable
Geozone.all.order("name") Geozone.all.order("name")
end end
def calculate_percentage(fraction, total) def geozone_stats
return 0.0 if total.zero? geozones.map { |geozone| GeozoneStats.new(geozone, participants) }
(fraction * 100.0 / total).round(3)
end end
def range_description(start, finish) def range_description(start, finish)

24
lib/geozone_stats.rb Normal file
View File

@@ -0,0 +1,24 @@
class GeozoneStats
attr_reader :geozone, :participants
def initialize(geozone, participants)
@geozone = geozone
@participants = participants
end
def geozone_participants
participants.where(geozone: geozone)
end
def name
geozone.name
end
def count
geozone_participants.count
end
def percentage
PercentageCalculator.calculate(count, participants.count)
end
end

View File

@@ -0,0 +1,7 @@
module PercentageCalculator
def self.calculate(fraction, total)
return 0.0 if total.zero?
(fraction * 100.0 / total).round(3)
end
end

View File

@@ -0,0 +1,44 @@
require "rails_helper"
describe GeozoneStats do
let(:winterfell) { create(:geozone, name: "Winterfell") }
let(:riverlands) { create(:geozone, name: "Riverlands") }
describe "#name" do
let(:stats) { GeozoneStats.new(winterfell, []) }
it "returns the geozone name" do
expect(stats.name).to eq "Winterfell"
end
end
describe "#count" do
before do
2.times { create(:user, geozone: winterfell) }
1.times { create(:user, geozone: riverlands) }
end
let(:winterfell_stats) { GeozoneStats.new(winterfell, User.all) }
let(:riverlands_stats) { GeozoneStats.new(riverlands, User.all) }
it "counts participants from the geozone" do
expect(winterfell_stats.count).to eq 2
expect(riverlands_stats.count).to eq 1
end
end
describe "#percentage" do
before do
2.times { create(:user, geozone: winterfell) }
1.times { create(:user, geozone: riverlands) }
end
let(:winterfell_stats) { GeozoneStats.new(winterfell, User.all) }
let(:riverlands_stats) { GeozoneStats.new(riverlands, User.all) }
it "calculates percentage relative to the amount of participants" do
expect(winterfell_stats.percentage).to eq 66.667
expect(riverlands_stats.percentage).to eq 33.333
end
end
end