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 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



123
124
125
126
127
128
129
130
131
# File 'lib/virtus/attribute.rb', line 123

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:



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

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:



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

def default
  @default
end

#nameSymbol (readonly)

Returns name of the attribute

Examples:

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

Returns:



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

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:



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

def options
  @options
end

Class Method Details

.build(name, type = Object, 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) (defaults to: Object)

    optional type class of an attribute

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

    optional extra options hash

Returns:



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

def self.build(name, type = Object, 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


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

def self.determine_type(class_or_name)
  case class_or_name
  when ::Class
    Attribute::EmbeddedValue.determine_type(class_or_name) || super
  when ::String
    super
  when ::Enumerable
    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



108
109
110
# File 'lib/virtus/attribute.rb', line 108

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



218
219
220
# File 'lib/virtus/attribute.rb', line 218

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)


249
250
251
252
253
# File 'lib/virtus/attribute.rb', line 249

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)


262
263
264
265
# File 'lib/virtus/attribute.rb', line 262

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)


274
275
276
277
# File 'lib/virtus/attribute.rb', line 274

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



158
159
160
161
162
163
164
165
166
# File 'lib/virtus/attribute.rb', line 158

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



177
178
179
# File 'lib/virtus/attribute.rb', line 177

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:



142
143
144
# File 'lib/virtus/attribute.rb', line 142

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:



284
285
286
# File 'lib/virtus/attribute.rb', line 284

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:



293
294
295
# File 'lib/virtus/attribute.rb', line 293

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)


189
190
191
# File 'lib/virtus/attribute.rb', line 189

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)


201
202
203
204
# File 'lib/virtus/attribute.rb', line 201

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:



238
239
240
# File 'lib/virtus/attribute.rb', line 238

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