def can? holder, action, obj
      obj = obj.to_s if obj.is_a? Symbol
      action = action.to_s

      return :abstain unless actions.include? action

      # Handle String permissions
      if obj.is_a? String
        if obj == conditions[:equals][:'*target_name']
          return target_type
        else
          return :abstain
        end
      end

      # Model permissions
      # Attempts to abstain by finding a condition or attribute where comparisons fail (and thus this target would be unapplicable)
      conditions.each do |comparator_name, fields_hash|
        comparator = Scram::DSL::Definitions::COMPARATORS[comparator_name.to_sym]
        fields_hash.each do |field, model_value|
          # Either gets the model's attribute or gets the DSL defined condition.
          # Abstains if neither can be reached
          attribute = begin obj.send(:"#{field}") rescue return :abstain end

          # Special value substitutions
          (model_value = holder.scram_compare_value) if model_value.to_s == "*holder"
          # Abstain if this target doesn't apply to obj in any of its attributes
          return :abstain unless comparator.call(attribute, model_value)
        end
      end

      return target_type
    end
def can? holder, action, obj
      obj = obj.to_s if obj.is_a? Symbol
      action = action.to_s

      return :abstain unless actions.include? action

      # Handle String permissions
      if obj.is_a? String
        if obj == conditions[:equals][:'*target_name']
          return target_type
        else
          return :abstain
        end
      end

      # Model permissions
      # Attempts to abstain by finding a condition or attribute where comparisons fail (and thus this target would be unapplicable)
      conditions.each do |comparator_name, fields_hash|
        comparator = Scram::DSL::Definitions::COMPARATORS[comparator_name.to_sym]
        fields_hash.each do |field, model_value|
          # Either gets the model's attribute or gets the DSL defined condition.
          # Abstains if neither can be reached
          attribute = begin obj.send(:"#{field}") rescue return :abstain end

          # Special value substitutions
          (model_value = holder.scram_compare_value) if model_value.to_s == "*holder"
          # Abstain if this target doesn't apply to obj in any of its attributes
          return :abstain unless comparator.call(attribute, model_value)
        end
      end

      return target_type
    end
Checks if a {Scram::Holder} can perform some action on an object given this target's conditions and allow-stance.

 Scram allows for special names:
   To make this target applicable to a string, use a key `*target_name` with value of the string permission.
   To compare a value to a holder, use `*holder` for a value. To compare a value to a custom condition defined by {Scram::DSL::Builders::ConditionBuilder}
   use an * before a key name (this name should match the one defined in your model).
 @param holder [Scram::Holder] The actor
 @param action [String] What the user is trying to do to obj
 @param obj [Object] The receiver of the action
 @return [Symbol] This target's opinion on an action and object. :allow and :deny mean this target explicitly defines
   its opinion, while :abstain means that this Target is not applicable to the action, and so has no opinion.