Class: Virtus::Attribute Abstract

Inherits:
Object
  • Object
show all
Extended by:
DescendantsTracker, Options, TypeLookup
Defined in:
lib/virtus/attribute.rb,
lib/virtus/attribute/set.rb,
lib/virtus/attribute/date.rb,
lib/virtus/attribute/hash.rb,
lib/virtus/attribute/time.rb,
lib/virtus/attribute/array.rb,
lib/virtus/attribute/class.rb,
lib/virtus/attribute/float.rb,
lib/virtus/attribute/object.rb,
lib/virtus/attribute/string.rb,
lib/virtus/attribute/symbol.rb,
lib/virtus/attribute/boolean.rb,
lib/virtus/attribute/decimal.rb,
lib/virtus/attribute/integer.rb,
lib/virtus/attribute/numeric.rb,
lib/virtus/attribute/date_time.rb,
lib/virtus/attribute/collection.rb,
lib/virtus/attribute/default_value.rb,
lib/virtus/attribute/embedded_value.rb,
lib/virtus/attribute/default_value/from_symbol.rb,
lib/virtus/attribute/embedded_value/from_struct.rb,
lib/virtus/attribute/default_value/from_callable.rb,
lib/virtus/attribute/default_value/from_clonable.rb,
lib/virtus/attribute/embedded_value/from_open_struct.rb

Overview

This class is abstract.

Abstract class implementing base API for attribute types

Direct Known Subclasses

Object

Defined Under Namespace

Classes: Array, Boolean, Class, Collection, Date, DateTime, Decimal, DefaultValue, EmbeddedValue, Float, Hash, Integer, Numeric, Object, Set, String, Symbol, Time

Constant Summary

Constants included from TypeLookup

TypeLookup::TYPE_FORMAT

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from DescendantsTracker

add_descendant, descendants

Methods included from TypeLookup

determine_type, extended, primitive

Methods included from Options

accept_options, accepted_options

Constructor Details

#initialize(name, options = {}) ⇒ undefined

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Initializes an attribute instance

Parameters:

  • name (#to_sym)

    the name of an attribute

  • options (#to_hash) (defaults to: {})

    hash of extra options which overrides defaults set on an attribute class



120
121
122
123
124
125
126
127
128
# File 'lib/virtus/attribute.rb', line 120

def initialize(name, options = {})
  @name                   = name.to_sym
  @options                = self.class.options.merge(options).freeze
  @instance_variable_name = "@#{@name}".to_sym
  @primitive              = @options.fetch(:primitive)
  @coercion_method        = @options.fetch(:coercion_method)
  @default                = DefaultValue.build(@options[:default])
  initialize_visibility
end

Instance Attribute Details

#coercion_methodSymbol (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns method name that should be used for coerceing

Returns:



38
39
40
# File 'lib/virtus/attribute.rb', line 38

def coercion_method
  @coercion_method
end

#defaultObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns default value

Returns:



45
46
47
# File 'lib/virtus/attribute.rb', line 45

def default
  @default
end

#nameSymbol (readonly)

Returns name of the attribute

Examples:

User.attributes[:age].name  # => :age

Returns:



24
25
26
# File 'lib/virtus/attribute.rb', line 24

def name
  @name
end

#optionsHash (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns options hash for the attribute

Returns:



31
32
33
# File 'lib/virtus/attribute.rb', line 31

def options
  @options
end

Class Method Details

.build(name, type, options = {}) ⇒ Attribute

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Builds an attribute instance

Parameters:

  • name (Symbol)

    the name of an attribute

  • type (Class)

    the type class of an attribute

  • options (#to_hash) (defaults to: {})

    the extra options hash

Returns:



61
62
63
64
65
66
# File 'lib/virtus/attribute.rb', line 61

def self.build(name, type, options = {})
  attribute_class = determine_type(type) or
    raise ArgumentError, "#{type.inspect} does not map to an attribute type"
  attribute_options = attribute_class.merge_options(type, options)
  attribute_class.new(name, attribute_options)
end

.determine_type(class_or_name) ⇒ Class

Determine attribute type based on class or name

Returns Attribute::EmbeddedValue if a virtus class is passed

Examples:

address_class = Class.new { include Virtus }
Virtus::Attribute.determine_type(address_class) # => Virtus::Attribute::EmbeddedValue

Returns:

See Also:

  • Support::TypeLookup.determine_type


81
82
83
84
85
86
87
88
89
90
# File 'lib/virtus/attribute.rb', line 81

def self.determine_type(class_or_name)
  case class_or_name
  when ::Class
    Attribute::EmbeddedValue.determine_type(class_or_name) || super
  when ::Array, ::Set
    super(class_or_name.class)
  else
    super
  end
end

.merge_options(type, options) ⇒ Hash

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

TODO:

add type arg to Attribute#initialize signature and handle there?

A hook for Attributes to update options based on the type from the caller

Parameters:

  • type (Object)

    The raw type, typically given by the caller of ClassMethods#attribute

  • options (Hash)

    Attribute configuration options

Returns:

  • (Hash)

    New Hash instance, potentially updated with information from the args



105
106
107
# File 'lib/virtus/attribute.rb', line 105

def self.merge_options(type, options)
  options
end

Instance Method Details

#coerce(value) ⇒ Object

Converts the given value to the primitive type

Examples:

attribute.coerce(value)  # => primitive_value

Parameters:

  • value (Object)

    the value

Returns:

  • (Object)

    nil, original value or value converted to the primitive type



215
216
217
# File 'lib/virtus/attribute.rb', line 215

def coerce(value)
  Coercion[value.class].public_send(coercion_method, value)
end

#define_accessor_methods(mod) ⇒ self

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Define reader and writer methods for an Attribute

Parameters:

Returns:

  • (self)


246
247
248
249
250
# File 'lib/virtus/attribute.rb', line 246

def define_accessor_methods(mod)
  define_reader_method(mod)
  define_writer_method(mod)
  self
end

#define_reader_method(mod) ⇒ self

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Creates an attribute reader method

Parameters:

  • mod (Module)

Returns:

  • (self)


259
260
261
262
# File 'lib/virtus/attribute.rb', line 259

def define_reader_method(mod)
  mod.define_reader_method(self, name, @reader_visibility)
  self
end

#define_writer_method(mod) ⇒ self

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Creates an attribute writer method

Parameters:

  • mod (Module)

Returns:

  • (self)


271
272
273
274
# File 'lib/virtus/attribute.rb', line 271

def define_writer_method(mod)
  mod.define_writer_method(self, "#{name}=".to_sym, @writer_visibility)
  self
end

#get(instance) ⇒ Object

Returns value of an attribute for the given instance

Sets the default value if an ivar is not set and default value is configured

Examples:

attribute.get(instance)  # => value

Returns:

  • (Object)

    value of an attribute



155
156
157
158
159
160
161
162
163
# File 'lib/virtus/attribute.rb', line 155

def get(instance)
  if instance.instance_variable_defined?(@instance_variable_name)
    get!(instance)
  else
    value = default.call(instance, self)
    set!(instance, value)
    value
  end
end

#get!(instance) ⇒ Object

Returns the instance variable of the attribute

Examples:

attribute.get!(instance)  # => value

Returns:

  • (Object)

    value of an attribute



174
175
176
# File 'lib/virtus/attribute.rb', line 174

def get!(instance)
  instance.instance_variable_get(@instance_variable_name)
end

#inspectString

Returns a concise string representation of the attribute instance

Examples:

attribute = Virtus::Attribute::String.new(:name)
attribute.inspect # => #<Virtus::Attribute::String @name=:name>

Returns:



139
140
141
# File 'lib/virtus/attribute.rb', line 139

def inspect
  "#<#{self.class.inspect} @name=#{name.inspect}>"
end

#public_reader?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a Boolean indicating whether the reader method is public

Returns:



281
282
283
# File 'lib/virtus/attribute.rb', line 281

def public_reader?
  @reader_visibility == :public
end

#public_writer?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a Boolean indicating whether the writer method is public

Returns:



290
291
292
# File 'lib/virtus/attribute.rb', line 290

def public_writer?
  @writer_visibility == :public
end

#set(instance, value) ⇒ self

Sets the value on the instance

Examples:

attribute.set(instance, value)  # => value

Returns:

  • (self)


186
187
188
# File 'lib/virtus/attribute.rb', line 186

def set(instance, value)
  set!(instance, coerce(value))
end

#set!(instance, value) ⇒ self

Sets instance variable of the attribute

Examples:

attribute.set!(instance, value)  # => value

Returns:

  • (self)


198
199
200
201
# File 'lib/virtus/attribute.rb', line 198

def set!(instance, value)
  instance.instance_variable_set(@instance_variable_name, value)
  self
end

#value_coerced?(value) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Is the given value coerced into the target type for this attribute?

Examples:

string_attribute = Virtus::Attribute::String.new(:str)
string_attribute.value_coerced?('foo')        # => true
string_attribute.value_coerced?(:foo)         # => false
integer_attribute = Virtus::Attribute::Integer.new(:integer)
integer_attribute.value_coerced?(5)           # => true
integer_attribute.value_coerced?('5')         # => false
date_attribute = Virtus::Attribute::Date.new(:date)
date_attribute.value_coerced?('2011-12-31')   # => false
date_attribute.value_coerced?(Date.today)     # => true

Returns:



235
236
237
# File 'lib/virtus/attribute.rb', line 235

def value_coerced?(value)
  @primitive === value
end