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