module Refine::Conditions module HasClauses def self.included(klass) klass.class_eval do mattr_accessor :default_clause_display_map, default: {}, instance_accessor: false end end def boot_has_clauses @show_clauses = {} add_rules({ clause: "required" }) with_meta({ clauses: get_clauses }) add_ensurance(ensure_clauses) before_validate(before_clause_validation) end def clause_display_map @clause_display_map ||= {} end def before_clause_validation(input = []) proc do |input| if input.present? current_clause = clauses.select{ |clause| clause.id == input[:clause] } if current_clause.present? add_rules(current_clause[0].rules) end end end end def custom_clauses [] end def remap_clause_displays(map) clause_display_map.merge!(map) self end def only_clauses(specific_clauses) # Remove all clauses clauses.map(&:id).each {|clause_id| update_show_clauses(clause_id, false) } # Add specific clauses by id, not by fully qualified clause specific_clauses.each {|clause| update_show_clauses(clause, true) } self end def with_clauses(clauses_to_include) clauses_to_include.each {|clause| update_show_clauses(clause, true) } self end def without_clauses(clauses_to_exclude) clauses_to_exclude.each {|clause| update_show_clauses(clause, false) } self end def update_show_clauses(clause, value) @show_clauses.merge!({"#{clause}": value}) end def ensure_clauses proc do clauses = get_clauses.call if clauses.any? clauses.each { |clause| ensure_clause(clause) } else errors.add(:base, I18n.t("refine.refine_blueprints.has_clauses.not_determined")) raise Errors::ConditionClauseError, "#{errors.full_messages}" end end end def ensure_clause(clause) if !clause.is_a? Clause errors.add(:base, I18n.t("refine.refine_blueprints.has_clauses.must_be_instance_of", instance: "#{Clause::class}")) raise Errors::ConditionClauseError, "#{errors.full_messages}" end if clause.id.blank? || clause.display.blank? errors.add(:base, I18n.t("refine.refine_blueprints.has_clauses.must_have_id_and_display")) raise Errors::ConditionClauseError, "#{errors.full_messages}" end end def get_clause_by_id(id) clause = get_clauses.call().find{ |clause| clause.id == id } raise I18n.t("refine.refine_blueprints.has_clauses.not_found", id: id) unless clause clause end def get_clauses proc do returned_clauses = clauses.dup # Clause display map takes precedence over default display map. Merge order matters. map = self.class.default_clause_display_map.merge(clause_display_map) @show_clauses.each do |clause_id, rule| filterable_clause_index = returned_clauses.index{ |clause| clause.id.to_sym == clause_id } if rule == false returned_clauses.delete_at(filterable_clause_index) elsif rule == true add_clause = returned_clauses.find{|clause| clause.id.to_sym == clause_id } returned_clauses << add_clause if !add_clause end end # Rewrite display if the key exists in the map. returned_clauses.each do |clause| if map.key?(clause.id.to_sym) clause.display = map[clause.id.to_sym] end end returned_clauses end end end end