blob: ba4f28a978160e3e30d10990b6e96c1b5127848e (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
module NutrientVector
extend ActiveSupport::Concern
NUTRIENT_KEYS = %i[
nno3 p k ca mg s na cl si fe zn b mn cu mo nnh4
].freeze
included do
# Define simple readers (nno3, p, k, ...) that read from #nutrient_values
NUTRIENT_KEYS.each do |k|
define_method(k) { nutrient_values[k] }
end
end
# Hash-like access
def [](key)
key = key.to_sym
return nil unless NUTRIENT_KEYS.include?(key)
public_send(key)
end
def keys = NUTRIENT_KEYS
# Returns a copy to avoid accidental mutation
def to_h
NUTRIENT_KEYS.index_with { |k| public_send(k) }
end
# Iterate over pairs
def each_pair
return enum_for(:each_pair) unless block_given?
NUTRIENT_KEYS.each { |k| yield k, public_send(k) }
end
# Simple difference (self - other), useful for “how far from target?”
def delta_against(other)
NUTRIENT_KEYS.index_with { |k| (public_send(k).to_f) - (other.public_send(k).to_f) }
end
# Percent difference relative to other (e.g., measurement vs target)
# Returns 0 when both are 0, and nil when target is 0 but measurement isn’t.
def percent_diff_against(other)
NUTRIENT_KEYS.index_with do |k|
a = public_send(k).to_f
b = other.public_send(k).to_f
if b.zero? && a.zero?
0.0
elsif b.zero?
nil
else
((a - b) / b) * 100.0
end
end
end
end
|