From 8adf634d15f54a839989ecff75a28a12e66b345b Mon Sep 17 00:00:00 2001 From: Keenan Brock Date: Wed, 22 May 2024 21:09:43 -0400 Subject: [PATCH] Introduce unary data choice rules --- lib/floe.rb | 6 +++ lib/floe/workflow/choice_rule.rb | 2 +- lib/floe/workflow/choice_rule/data.rb | 53 +++++++------------ lib/floe/workflow/choice_rule/is_boolean.rb | 13 +++++ lib/floe/workflow/choice_rule/is_null.rb | 13 +++++ lib/floe/workflow/choice_rule/is_numeric.rb | 14 +++++ lib/floe/workflow/choice_rule/is_present.rb | 13 +++++ lib/floe/workflow/choice_rule/is_string.rb | 13 +++++ lib/floe/workflow/choice_rule/is_timestamp.rb | 19 +++++++ 9 files changed, 110 insertions(+), 36 deletions(-) create mode 100644 lib/floe/workflow/choice_rule/is_boolean.rb create mode 100644 lib/floe/workflow/choice_rule/is_null.rb create mode 100644 lib/floe/workflow/choice_rule/is_numeric.rb create mode 100644 lib/floe/workflow/choice_rule/is_present.rb create mode 100644 lib/floe/workflow/choice_rule/is_string.rb create mode 100644 lib/floe/workflow/choice_rule/is_timestamp.rb diff --git a/lib/floe.rb b/lib/floe.rb index 7b4368c17..611376ef2 100644 --- a/lib/floe.rb +++ b/lib/floe.rb @@ -13,6 +13,12 @@ require_relative "floe/workflow/choice_rule/not" require_relative "floe/workflow/choice_rule/or" require_relative "floe/workflow/choice_rule/and" +require_relative "floe/workflow/choice_rule/is_boolean" +require_relative "floe/workflow/choice_rule/is_null" +require_relative "floe/workflow/choice_rule/is_numeric" +require_relative "floe/workflow/choice_rule/is_present" +require_relative "floe/workflow/choice_rule/is_string" +require_relative "floe/workflow/choice_rule/is_timestamp" require_relative "floe/workflow/choice_rule/data" require_relative "floe/workflow/context" require_relative "floe/workflow/path" diff --git a/lib/floe/workflow/choice_rule.rb b/lib/floe/workflow/choice_rule.rb index ec60ee29b..c72419798 100644 --- a/lib/floe/workflow/choice_rule.rb +++ b/lib/floe/workflow/choice_rule.rb @@ -12,7 +12,7 @@ def build(payload) elsif (sub_payloads = payload["Or"]) Floe::Workflow::ChoiceRule::Or.new(payload, build_children(sub_payloads)) else - Floe::Workflow::ChoiceRule::Data.new(payload) + Floe::Workflow::ChoiceRule::Data.build(payload) end end diff --git a/lib/floe/workflow/choice_rule/data.rb b/lib/floe/workflow/choice_rule/data.rb index 9ae8749d2..ecff0b144 100644 --- a/lib/floe/workflow/choice_rule/data.rb +++ b/lib/floe/workflow/choice_rule/data.rb @@ -5,8 +5,26 @@ class Workflow class ChoiceRule class Data < Floe::Workflow::ChoiceRule COMPARE_KEYS = %w[IsNull IsPresent IsNumeric IsString IsBoolean IsTimestamp String Numeric Boolean Timestamp].freeze + DATA_RULES = { + "IsNull" => Floe::Workflow::ChoiceRule::IsNull, + "IsPresent" => Floe::Workflow::ChoiceRule::IsPresent, + "IsNumeric" => Floe::Workflow::ChoiceRule::IsNumeric, + "IsString" => Floe::Workflow::ChoiceRule::IsString, + "IsBoolean" => Floe::Workflow::ChoiceRule::IsBoolean, + "IsTimestamp" => Floe::Workflow::ChoiceRule::IsTimestamp, + } attr_reader :compare_key + attr_accessor :ref, :ref_path + + def self.build(payload) + compare_key = payload.keys.detect { |key| key.match?(/^(#{DATA_RULES.keys.join("|")})/) } + if compare_key + DATA_RULES[compare_key].new(payload) + else + Floe::Workflow::ChoiceRule::Data.new(payload) + end + end def initialize(*) super @@ -26,12 +44,6 @@ def true?(context, input) return false unless valid?(lhs) case compare_key - when "IsNull" then is_null?(lhs) - when "IsPresent" then is_present?(lhs) - when "IsNumeric" then is_numeric?(lhs) - when "IsString" then is_string?(lhs) - when "IsBoolean" then is_boolean?(lhs) - when "IsTimestamp" then is_timestamp?(lhs) when "StringEquals", "StringEqualsPath", "NumericEquals", "NumericEqualsPath", "BooleanEquals", "BooleanEqualsPath", @@ -63,38 +75,9 @@ def true?(context, input) private def valid?(value) - !value.nil? || %w[IsNull IsPresent].include?(compare_key) - end - - def is_null?(value) # rubocop:disable Naming/PredicateName - value.nil? - end - - def is_present?(value) # rubocop:disable Naming/PredicateName !value.nil? end - def is_numeric?(value) # rubocop:disable Naming/PredicateName - value.kind_of?(Integer) || value.kind_of?(Float) - end - - def is_string?(value) # rubocop:disable Naming/PredicateName - value.kind_of?(String) - end - - def is_boolean?(value) # rubocop:disable Naming/PredicateName - [true, false].include?(value) - end - - def is_timestamp?(value) # rubocop:disable Naming/PredicateName - require "date" - - DateTime.rfc3339(value) - true - rescue TypeError, Date::Error - false - end - def compare_value(context, input) @ref_path ? Path.value(@ref_path, context, input) : @ref end diff --git a/lib/floe/workflow/choice_rule/is_boolean.rb b/lib/floe/workflow/choice_rule/is_boolean.rb new file mode 100644 index 000000000..5dcc7ac74 --- /dev/null +++ b/lib/floe/workflow/choice_rule/is_boolean.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Floe + class Workflow + class ChoiceRule + class IsBoolean < Floe::Workflow::ChoiceRule + def true?(context, input) + [true, false].include?(variable_value(context, input)) + end + end + end + end +end diff --git a/lib/floe/workflow/choice_rule/is_null.rb b/lib/floe/workflow/choice_rule/is_null.rb new file mode 100644 index 000000000..484b48baf --- /dev/null +++ b/lib/floe/workflow/choice_rule/is_null.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Floe + class Workflow + class ChoiceRule + class IsNull < Floe::Workflow::ChoiceRule + def true?(context, input) + variable_value(context, input).nil? + end + end + end + end +end diff --git a/lib/floe/workflow/choice_rule/is_numeric.rb b/lib/floe/workflow/choice_rule/is_numeric.rb new file mode 100644 index 000000000..f738e5f7c --- /dev/null +++ b/lib/floe/workflow/choice_rule/is_numeric.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Floe + class Workflow + class ChoiceRule + class IsNumeric < Floe::Workflow::ChoiceRule + def true?(context, input) + value = variable_value(context, input) + value.kind_of?(Integer) || value.kind_of?(Float) + end + end + end + end +end diff --git a/lib/floe/workflow/choice_rule/is_present.rb b/lib/floe/workflow/choice_rule/is_present.rb new file mode 100644 index 000000000..df75d24ad --- /dev/null +++ b/lib/floe/workflow/choice_rule/is_present.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Floe + class Workflow + class ChoiceRule + class IsPresent < IsNull + def true?(context, input) + !variable_value(context, input).nil? + end + end + end + end +end diff --git a/lib/floe/workflow/choice_rule/is_string.rb b/lib/floe/workflow/choice_rule/is_string.rb new file mode 100644 index 000000000..8ee5e88ca --- /dev/null +++ b/lib/floe/workflow/choice_rule/is_string.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Floe + class Workflow + class ChoiceRule + class IsString < Floe::Workflow::ChoiceRule + def true?(context, input) + variable_value(context, input).kind_of?(String) + end + end + end + end +end diff --git a/lib/floe/workflow/choice_rule/is_timestamp.rb b/lib/floe/workflow/choice_rule/is_timestamp.rb new file mode 100644 index 000000000..06b39bc03 --- /dev/null +++ b/lib/floe/workflow/choice_rule/is_timestamp.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Floe + class Workflow + class ChoiceRule + class IsTimestamp < Floe::Workflow::ChoiceRule + def true?(context, input) + value = variable_value(context, input) + require "date" + + DateTime.rfc3339(value) + true + rescue TypeError, Date::Error + false + end + end + end + end +end