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

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

Constant Summary

Constants included from TypeLookup

TypeLookup::EXTRA_CONST_ARGS, 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, 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



145
146
147
148
149
150
151
152
153
# File 'lib/virtus/attribute.rb', line 145

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.new(self, @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:

  • (Symbol)


59
60
61
# File 'lib/virtus/attribute.rb', line 59

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:



66
67
68
# File 'lib/virtus/attribute.rb', line 66

def default
  @default
end

#instance_variable_nameSymbol (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 instance variable name of the attribute

Returns:

  • (Symbol)


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

def instance_variable_name
  @instance_variable_name
end

#nameSymbol (readonly)

Returns name of the attribute

Examples:

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

Returns:

  • (Symbol)


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

#reader_visibilitySymbol (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 reader visibility

Returns:

  • (Symbol)


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

def reader_visibility
  @reader_visibility
end

#writer_visibilitySymbol (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 write visibility

Returns:

  • (Symbol)


52
53
54
# File 'lib/virtus/attribute.rb', line 52

def writer_visibility
  @writer_visibility
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:



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

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


102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/virtus/attribute.rb', line 102

def self.determine_type(class_or_name)
  case class_or_name
  when ::Class
    if class_or_name <= Virtus
      Attribute::EmbeddedValue
    else
      super
    end
  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



130
131
132
# File 'lib/virtus/attribute.rb', line 130

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



240
241
242
# File 'lib/virtus/attribute.rb', line 240

def coerce(value)
  Coercion[value.class].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)


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

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)


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

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)


296
297
298
299
# File 'lib/virtus/attribute.rb', line 296

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



180
181
182
183
184
185
186
187
188
# File 'lib/virtus/attribute.rb', line 180

def get(instance)
  if instance.instance_variable_defined?(instance_variable_name)
    get!(instance)
  else
    value = default.evaluate(instance)
    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



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

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:



164
165
166
# File 'lib/virtus/attribute.rb', line 164

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:



306
307
308
# File 'lib/virtus/attribute.rb', line 306

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:



315
316
317
# File 'lib/virtus/attribute.rb', line 315

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)


211
212
213
# File 'lib/virtus/attribute.rb', line 211

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)


223
224
225
226
# File 'lib/virtus/attribute.rb', line 223

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:



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

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