class T::Props::Decorator
def prop_defined(name, cls, rules={})
def prop_defined(name, cls, rules={}) cls = T::Utils.resolve_alias(cls) if T::Utils::Nilable.is_union_with_nilclass(cls) # :_tnilable is introduced internally for performance purpose so that clients do not need to call # T::Utils::Nilable.is_tnilable(cls) again. # It is strictly internal: clients should always use T::Props::Utils.required_prop?() or # T::Props::Utils.optional_prop?() for checking whether a field is required or optional. rules[:_tnilable] = true end name = name.to_sym type = cls if !cls.is_a?(Module) cls = convert_type_to_class(cls) end type_object = smart_coerce(type, enum: rules[:enum]) prop_validate_definition!(name, cls, rules, type_object) # Retrive the possible underlying object with T.nilable. type = T::Utils::Nilable.get_underlying_type(type) sensitivity_and_pii = {sensitivity: rules[:sensitivity]} if defined?(Opus) && defined?(Opus::Sensitivity) && defined?(Opus::Sensitivity::Utils) sensitivity_and_pii = Opus::Sensitivity::Utils.normalize_sensitivity_and_pii_annotation(sensitivity_and_pii) # We check for Class so this is only applied on concrete # documents/models; We allow mixins containing props to not # specify their PII nature, as long as every class into which they # are ultimately included does. # if sensitivity_and_pii[:pii] && @class.is_a?(Class) && !T.unsafe(@class).contains_pii? raise ArgumentError.new( 'Cannot include a pii prop in a class that declares `contains_no_pii`' ) end end rules = rules.merge( # TODO: The type of this element is confusing. We should refactor so that # it can be always `type_object` (a PropType) or always `cls` (a Module) type: type, type_object: type_object, accessor_key: "@#{name}".to_sym, sensitivity: sensitivity_and_pii[:sensitivity], pii: sensitivity_and_pii[:pii], # extra arbitrary metadata attached by the code defining this property extra: rules[:extra]&.freeze, ) validate_not_missing_sensitivity(name, rules) # for backcompat (the `:array` key is deprecated but because the name is # so generic it's really hard to be sure it's not being relied on anymore) if type.is_a?(T::Types::TypedArray) inner = T::Utils::Nilable.get_underlying_type(type.type) if inner.is_a?(Module) rules[:array] = inner end end rules[:setter_proc] = T::Props::Private::SetterFactory.build_setter_proc(@class, name, rules).freeze add_prop_definition(name, rules) # NB: using `without_accessors` doesn't make much sense unless you also define some other way to # get at the property (e.g., Chalk::ODM::Document exposes `get` and `set`). define_getter_and_setter(name, rules) unless rules[:without_accessors] if rules[:foreign] && rules[:foreign_hint_only] raise ArgumentError.new(":foreign and :foreign_hint_only are mutually exclusive.") end handle_foreign_option(name, cls, rules, rules[:foreign]) if rules[:foreign] handle_foreign_hint_only_option(name, cls, rules[:foreign_hint_only]) if rules[:foreign_hint_only] handle_redaction_option(name, rules[:redaction]) if rules[:redaction] end