summaryrefslogtreecommitdiff
path: root/app/models/concerns/nutrient_vector.rb
diff options
context:
space:
mode:
authorMarius Peter <dev@marius-peter.com>2025-11-23 17:54:45 +0100
committerMarius Peter <dev@marius-peter.com>2025-11-23 17:54:45 +0100
commitfa77a691ce0cc8941fe470a762f352b27f4f0563 (patch)
tree08916174840a7896fc59633cc59fab931e7012c2 /app/models/concerns/nutrient_vector.rb
parent73283f2f5153c77f72b6a29e98f173628f5e1057 (diff)
Last commit.HEADmaster
Diffstat (limited to 'app/models/concerns/nutrient_vector.rb')
-rw-r--r--app/models/concerns/nutrient_vector.rb55
1 files changed, 55 insertions, 0 deletions
diff --git a/app/models/concerns/nutrient_vector.rb b/app/models/concerns/nutrient_vector.rb
new file mode 100644
index 0000000..ba4f28a
--- /dev/null
+++ b/app/models/concerns/nutrient_vector.rb
@@ -0,0 +1,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
Copyright 2019--2026 Marius PETER