Skip to content

Instantly share code, notes, and snippets.

@gecugamo
Last active January 9, 2025 16:37
Show Gist options
  • Save gecugamo/b3633ac2d65589418ba9f6fe99612731 to your computer and use it in GitHub Desktop.
Save gecugamo/b3633ac2d65589418ba9f6fe99612731 to your computer and use it in GitHub Desktop.
Dynamic Rules
class DynamicRuleAttributeService
METHOD_DICTIONARY = {
"coverage.coverage_a" => :coverage_a,
"coverage.coverage_b" => :coverage_b
}.freeze
# Finds the value for a given attribute alias
# @param attr_alias [String] Alias of attribute to find
# @return [Object, nil] Result of the corresponding method call or nil if not found
def self.call(policy, attr_alias)
method_name = METHOD_DICTIONARY[attr_alias]
raise ArgumentError, "Unknown alias: #{attr_alias}" unless method_name
method(method_name).call(policy)
end
private
# Define methods corresponding to dictionary keys
def self.coverage_a(policy)
policy&.coverage&.coverage_a
end
def self.coverage_b(policy)
policy&.coverage&.coverage_b
end
end
class DynamicRuleOperatorService
METHOD_DICTIONARY = {
"added" => :added,
"removed" => :removed
}.freeze
def self.call(operator_alias, attribute, value)
method_name = METHOD_DICTIONARY[operator_alias]
raise ArgumentError, "Unknown alias: #{attr_alias}" unless method_name
method(method_name).call(attribute, value)
end
private
def self.added(attribute, value)
attribute == 10_000
end
end
class DynamicRuleEvaluatorService
attr_reader :policy, :rules
def initialize(policy, rules)
@policy = policy
@rules = rules
end
# @return [Boolean]
def call
result = true
rules.each do |rule|
attribute = rule["attribute"]
operator = rule["operator"]
value = rule["value"]
should_lookup_value = rule["should_lookup_value"]
if should_lookup_value
value = DynamicRuleAttributeService.call(policy, value)
end
attribute_value = DynamicRuleAttributeService.call(policy, attribute)
current_result = DynamicRuleOperatorService.call(
operator,
attribute_value,
value
)
result = result && current_result
break unless result
end
result
end
end
# Example
class Coverage
def coverage_a
10_000
end
def coverage_b
"10%"
end
end
class Policy
def coverage
Coverage.new
end
end
policy = Policy.new
rules = [
{
"attribute" => "coverage.coverage_a",
"operator" => "added",
"value" => nil
},
{
"attribute" => "coverage.coverage_b",
"operator" => "added",
"value" => nil
}
]
evaluator = DynamicRuleEvaluatorService.new(policy, rules)
puts evaluator.call
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment