class RuleSetProcessor class InvalidRule < ::ArgumentError end def process_all(rule_sets, email) rule_sets.each { |rule_set| email = process(rule_set, email) } email end def process(rule_set, email) return email unless rule_set.enabled? if evaluate_rules(rule_set, email) email = execute_actions(rule_set.actions, email) end email end def evaluate_rules(rule_set, email) rule_set_result = true rule_set_result = catch(:done) { rule_set.rules.each do |rule| next unless rule.enabled? subjects = prepare_subjects(rule, email) rule_result = apply_rule(subjects, rule) rule_result = !rule_result if rule.inverted? rule_set_result = apply_operator(rule_set_result, rule_set.operator, rule_result) rescue InvalidRule => ex Rails.logger.error "Skipped rule##{rule.id} '#{rule.name}' - #{ex.inspect}" next end } rule_set_result end def execute_actions(actions, email) actions.each do |action| next unless action.enabled? klass = action.class_name.constantize email_action = klass.new email = email_action.process(email) rescue NameError => ex Rails.logger.error "Skipped action##{action.id} '#{action.name}' - #{ex.inspect}" raise InvalidRule, ex.message end email end def prepare_subjects(rule, email) case rule.subject_type.downcase when "header" Array(email.header_values(rule.subject_value)) when "body" Array(email.plain_body) else raise InvalidRule, "Unrecognized subject type '#{rule.subject_type}'" end end private def apply_rule(subjects, rule) case rule.condition_type.downcase when "match", "matches" subjects.any? { |subject| pattern = Regexp.new(rule.condition_value) subject.match? } when "equal", "equals" subjects.any? { |subject| subject == rule.condition_value } when "start", "starts" subjects.any? { |subject| subject.starts_with? rule.condition_value } when "end", "ends" subjects.any? { |subject| subject.ends_with? rule.condition_value } when "contain", "contains" subjects.any? { |subject| subject.include? rule.condition_value } when "exist", "exists" subjects.any? { |subject| subject.exists? } when "empty" subjects.all? { |subject| subject.empty? } when "date_before" # subjects.all? { |subject| # subject.empty? # } when "date_after" # subjects.all? { |subject| # subject.empty? # } else raise InvalidRule, "Unrecognized condition type '#{rule. condition_type}'" end end def apply_operator(state, operator, result) case operator.upcase when "AND" if result (state and result) else throw :done, false end when "OR" if result throw :done, true else (state or result) end # when "XOR" # (state or result) and !(rules_state and result) else raise InvalidRule, "Unrecognized operator '#{operator}'" end end end