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



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

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



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

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



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

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)


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

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)


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

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)


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

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



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

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



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

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:



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

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:



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

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:



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

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)


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

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)


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

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:



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

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