main
  1# frozen_string_literal: true
  2
  3module Scim
  4  module Kit
  5    module V2
  6      # Represents a SCIM Attribute
  7      class Attribute
  8        include ::ActiveModel::Validations
  9        include Attributable
 10        include Templatable
 11        attr_reader :_type
 12        attr_reader :_resource
 13        attr_reader :_value
 14
 15        validate :presence_of_value, if: proc { |x| x._type.required }
 16        validate :inclusion_of_value, if: proc { |x| x._type.canonical_values }
 17        validate :validate_type, unless: proc { |x| x.complex? }
 18        validate :validate_complex, if: proc { |x| x.complex? }
 19        validate :multiple, if: proc { |x| x.multi_valued && !x.complex? }
 20
 21        delegate :complex?, :multi_valued, to: :_type
 22
 23        def initialize(resource:, type:, value: nil)
 24          @_type = type
 25          @_value = value || type.multi_valued ? [] : nil
 26          @_resource = resource
 27
 28          define_attributes_for(resource, type.attributes)
 29        end
 30
 31        def _assign(new_value, coerce: false)
 32          @_value = coerce ? _type.coerce(new_value) : new_value
 33        end
 34
 35        def _value=(new_value)
 36          _assign(new_value, coerce: true)
 37        end
 38
 39        def renderable?
 40          return false if server_only?
 41          return false if client_only?
 42          return false if restricted?
 43
 44          true
 45        end
 46
 47        def each_value(&block)
 48          Array(_value).each(&block)
 49        end
 50
 51        private
 52
 53        def server_only?
 54          read_only? && _resource.mode?(:client)
 55        end
 56
 57        def client_only?
 58          write_only? && (_resource.mode?(:server) || _value.blank?)
 59        end
 60
 61        def restricted?
 62          _resource.mode?(:server) && _type.returned == Returned::NEVER
 63        end
 64
 65        def presence_of_value
 66          return unless _type.required && _value.blank?
 67
 68          errors.add(_type.name, I18n.t('errors.messages.blank'))
 69        end
 70
 71        def inclusion_of_value
 72          return if _type.canonical_values.include?(_value)
 73
 74          errors.add(_type.name, I18n.t('errors.messages.inclusion'))
 75        end
 76
 77        def validate_type
 78          return if _value.nil?
 79          return if _type.valid?(_value)
 80
 81          errors.add(_type.name, I18n.t('errors.messages.invalid'))
 82        end
 83
 84        def validate_complex
 85          validates_with ComplexAttributeValidator
 86        end
 87
 88        def multiple
 89          return unless _value.respond_to?(:to_a)
 90
 91          duped_type = _type.dup
 92          duped_type.multi_valued = false
 93          _value.to_a.each do |x|
 94            unless duped_type.valid?(x)
 95              errors.add(duped_type.name, I18n.t('errors.messages.invalid'))
 96            end
 97          end
 98        end
 99
100        def read_only?
101          _type.mutability == Mutability::READ_ONLY
102        end
103
104        def write_only?
105          _type.mutability == Mutability::WRITE_ONLY
106        end
107      end
108    end
109  end
110end