Module: Ruby::Rego::Builtins::Aggregates
- Defined in:
- lib/ruby/rego/builtins/aggregates.rb
Overview
Built-in aggregation helpers.
Constant Summary collapse
- AGGREGATE_FUNCTIONS =
{ "count" => :count, "sum" => :sum, "product" => :product, "max" => :max, "min" => :min, "all" => :all, "any" => :any }.freeze
Class Method Summary collapse
-
.all(array) ⇒ Ruby::Rego::BooleanValue
-
.any(array) ⇒ Ruby::Rego::BooleanValue
-
.count(collection) ⇒ Ruby::Rego::NumberValue
-
.max(collection) ⇒ Ruby::Rego::Value
Return the largest element of an array or set.
-
.min(collection) ⇒ Ruby::Rego::Value
Return the smallest element of an array or set.
-
.product(collection) ⇒ Ruby::Rego::Value
Multiply an array or set of numbers.
-
.register! ⇒ Ruby::Rego::Builtins::BuiltinRegistry
-
.sum(collection) ⇒ Ruby::Rego::Value
Sum an array or set of numbers.
Class Method Details
.all(array) ⇒ Ruby::Rego::BooleanValue
133 134 135 136 |
# File 'lib/ruby/rego/builtins/aggregates.rb', line 133 def self.all(array) Base.assert_type(array, expected: ArrayValue, context: "all") BooleanValue.new(array.value.all?(&:truthy?)) end |
.any(array) ⇒ Ruby::Rego::BooleanValue
140 141 142 143 |
# File 'lib/ruby/rego/builtins/aggregates.rb', line 140 def self.any(array) Base.assert_type(array, expected: ArrayValue, context: "any") BooleanValue.new(array.value.any?(&:truthy?)) end |
.count(collection) ⇒ Ruby::Rego::NumberValue
42 43 44 45 46 47 48 49 50 |
# File 'lib/ruby/rego/builtins/aggregates.rb', line 42 def self.count(collection) Base.assert_type( collection, expected: [ArrayValue, ObjectValue, SetValue, StringValue], context: "count" ) NumberValue.new(collection.value.size) end |
.max(collection) ⇒ Ruby::Rego::Value
Return the largest element of an array or set. DIVERGENCE (pre-existing, tracked): OPA’s max/min
are polymorphic over its total value order — max(["a","b"]) -> "b", max([true,false]) -> true,
even mixed types max([1,"a"]) -> "a" — whereas this gem restricts max/min to numbers (a
non-number element maps to undefined via extract_finite_real). Generalizing to OPA’s value order
is its own number-model/ordering sweep item, not this (numeric-aggregates) scope.
105 106 107 108 109 110 111 112 113 114 |
# File 'lib/ruby/rego/builtins/aggregates.rb', line 105 def self.max(collection) numbers = extract_numeric_elements(collection, name: "max") ensure_non_empty(numbers, name: "max") # Among value-equal extrema OPA returns the LAST element (so max([1.50, 1.5]) -> 1.5, keeping # the later spelling). A single-pass reduce keeping the later element on a tie (the explicit # `>=` documents the tie-break) avoids the reversed-array copy that `reverse.max` would allocate. # rubocop:disable Style/MinMaxComparison Value.from_ruby(numbers.reduce { |best, number| number >= best ? number : best }) # rubocop:enable Style/MinMaxComparison end |
.min(collection) ⇒ Ruby::Rego::Value
Return the smallest element of an array or set. Number-only, like max — see it for the pre-existing divergence from OPA’s polymorphic min.
121 122 123 124 125 126 127 128 129 |
# File 'lib/ruby/rego/builtins/aggregates.rb', line 121 def self.min(collection) numbers = extract_numeric_elements(collection, name: "min") ensure_non_empty(numbers, name: "min") # OPA returns the LAST element among value-equal minima too; reduce keeping the later element # on a tie (single pass, no reversed-array copy). # rubocop:disable Style/MinMaxComparison Value.from_ruby(numbers.reduce { |best, number| number <= best ? number : best }) # rubocop:enable Style/MinMaxComparison end |
.product(collection) ⇒ Ruby::Rego::Value
Multiply an array or set of numbers. The OPA-faithful arithmetic (prec-64 big.Float fold with no integer fast-path) and the DoS magnitude cap live in Number.product; here an empty collection is the multiplicative identity 1 and a set is folded in ascending order by extract_numeric_elements.
69 70 71 72 |
# File 'lib/ruby/rego/builtins/aggregates.rb', line 69 def self.product(collection) numbers = extract_numeric_elements(collection, name: "product") Value.from_ruby(bounded_fold(:product, numbers)) end |
.register! ⇒ Ruby::Rego::Builtins::BuiltinRegistry
23 24 25 26 27 28 29 30 31 |
# File 'lib/ruby/rego/builtins/aggregates.rb', line 23 def self.register! registry = BuiltinRegistry.instance AGGREGATE_FUNCTIONS.each do |name, handler| register_function(registry, name, handler) end registry end |
.sum(collection) ⇒ Ruby::Rego::Value
Sum an array or set of numbers. The OPA-faithful arithmetic (integer fast-path vs prec-64 big.Float fold, and the int64-overflow handling) lives in Number.sum; here an empty collection sums to 0 and a set is deduplicated and folded in ascending order by extract_numeric_elements.
58 59 60 61 |
# File 'lib/ruby/rego/builtins/aggregates.rb', line 58 def self.sum(collection) numbers = extract_numeric_elements(collection, name: "sum") Value.from_ruby(bounded_fold(:sum, numbers)) end |